由于 java/kotlin 中不允许多重继承,因此利用接口默认方法很有用。给出的例子:
abstract class Animal {
fun beAnimal() {
println("I'm animal!")
}
}
abstract class Mammal : Animal() {
fun produceMilk() {
beAnimal().apply { println("Freesh milk!") }
}
}
abstract class AnimalWithBeak : Animal() {
fun quack() {
beAnimal().apply { println("Quack!") }
}
}
class Platypus : ??? // I want it to both produce milk and quack!
Run Code Online (Sandbox Code Playgroud)
如上所述,不允许使用多个基类,但我们可以使用接口:
abstract class Animal { fun beAnimal() { println("I'm animal!") } }
interface Mammal {
fun produceMilk() {
(this as Animal).beAnimal().apply …Run Code Online (Sandbox Code Playgroud) 我有几个关于Java 8中"新"接口的问题,我有以下代码:
public interface Drawable {
public void compileProgram();
public Program getProgram();
public boolean isTessellated();
public boolean isInstanced();
public int getInstancesCount();
public int getDataSize();
public FloatBuffer putData(final FloatBuffer dataBuffer);
public int getDataMode();
public boolean isShadowReceiver();
public boolean isShadowCaster(); //TODO use for AABB calculations
default public void drawDepthPass(final int offset, final Program depthNormalProgram, final Program depthTessellationProgram) {
Program depthProgram = (isTessellated()) ? depthTessellationProgram : depthNormalProgram;
if (isInstanced()) {
depthProgram.drawArraysInstanced(getDataMode(), offset, getDataSize(), getInstancesCount());
}
else {
depthProgram.drawArrays(getDataMode(), offset, getDataSize());
}
}
default …Run Code Online (Sandbox Code Playgroud) 如果我有两个接口使用相同的默认方法,并且都使用类实现/请参阅此程序.
interface alpha {
default void reset() {
System.out.println("This is alpha version of default");
}
}
interface beta {
default void reset() {
System.out.println("This is beta version of default");
}
}
class MyClass implements alpha, beta {
void display() {
System.out.println("This is not default");
}
}
class main_class {
public static void main(String args[]) {
MyClass ob = new MyClass();
ob.reset();
ob.display();
}
}
Run Code Online (Sandbox Code Playgroud)
然后会发生什么?而且这个程序我也得到了无关的错误.
今天遇到了这个问题,花了很多年时间试图重现/弄清楚发生了什么.有人可以解释为什么会发生这种情况,或者这是类型擦除/默认方法/ lambda/polymorphism的错误?取消注释默认方法可以使它运行正常,但我希望它能够按原样运行
输出:
Works fine with an object
Calling consume
Hello
Calling accept with context
Hello
Calling accept via consumer...
Exception in thread "main" java.lang.AbstractMethodError: Method test/LambdaTest$$Lambda$1.accept(Ljava/lang/Object;)V is abstract
at test.LambdaTest$$Lambda$1/834600351.accept(Unknown Source)
at test.LambdaTest.main(LambdaTest.java:24)
Run Code Online (Sandbox Code Playgroud)
码
package test;
import java.util.function.Consumer;
public class LambdaTest {
public static void main(String[] args) {
Consumer<Context> contextIgnoringObject = new ContextUnawareObject();
contextIgnoringObject.accept(new Context());
ContextIgnorer contextIgnoringLambda = () -> {
System.err.println("Hello");
};
System.err.println("Calling consume");
contextIgnoringLambda.consume();
System.err.println("Calling accept with context");
contextIgnoringLambda.accept(new Context());
Consumer<Context> consumer = contextIgnoringLambda;
System.err.println("Calling accept via …Run Code Online (Sandbox Code Playgroud) 一本书的问题:
在过去(Java 8之前版本),您被告知将方法添加到接口是一种糟糕的形式,因为它会破坏现有代码.现在您被告知可以添加新方法,前提是您还提供默认实现.
- 这有多安全?描述接口的新
stream方法Collection导致遗留代码编译失败的情况.- 二进制兼容性怎么样?来自JAR文件的遗留代码是否仍会运行?"
我的答案如下,但我不太确定.
stream和相同签名的方法时(例如,在实现的遗留类中Collection),它才是安全的.否则,这个旧的遗留代码将无法编译. 任何人都可以确认或拒绝这些答案,或者只是为这些答案添加更多参数,参考或清晰度吗?
这是一个显示我的问题的简化示例:
import java.util.List;
public interface SingleTask extends List<Runnable>, Runnable {
default Runnable get(final int x) {
if (x != 0) {
throw new IndexOutOfBoundsException();
}
return this;
}
default int size() {
return 1;
}
}
import java.util.AbstractList;
public class MyTask extends AbstractList<Runnable> implements SingleTask {
@Override
public void run() {
System.out.println("hello");
}
}
Run Code Online (Sandbox Code Playgroud)
在SingleTask我提供用于方法的实现get和size,它们是从仅抽象方法AbstractList.但是,当我编译时MyTask,我仍然会遇到如下错误:
MyTask类型必须实现继承的抽象方法AbstractCollection.size()
要么
MyTask.java:3:错误:MyTask不是抽象的,并且不会覆盖AbstractList中的抽象方法get(int)
(取决于编译器).我当然是使用java 8.
所以我有两个问题:
MyTask不复制整个代码的情况下使用这两种方法的最简单方法是什么?我想知道是否可以使用来自TestNG @BeforeMethod注释的接口的默认方法?
这是我试过的样本:
@Listeners(TestListener.class)
public interface ITestBase {
String baseUrl = Config.getProperty(Config.TEST_HOST);
String driverName = Config.getProperty(Config.BROWSER);
DriversEnum driverInstance = DriversEnum.valueOf(driverName.toUpperCase());
@BeforeMethod(alwaysRun = true)
default public void start() {
try {
driver.init();
DriverUnit.preconfigureDriver(Driver.driver.get());
driver.get().manage().deleteAllCookies();
driver.get().get(baseUrl);
} catch (TimeoutException e) {
Logger.logEnvironment("QT application is not available");
}
}
@AfterMethod(alwaysRun = true)
default public void end() {
if (driver.get() != null) {
try {
driver.get().quit();
} catch (UnreachableBrowserException e) {
Logger.logDebug("UnreachableBrowser on close");
} finally {
driver.remove();
}
}
}
Run Code Online (Sandbox Code Playgroud)
当我运行典型的TestNG测试方法时,如:
public …Run Code Online (Sandbox Code Playgroud) 当没有默认方法的接口扩展可序列化时,一切正常。但是,当该接口的默认方法出现时,我们将显示警告:
MyInterface.java:可序列化的类MyInterface没有serialVersionUID的定义
当我将该接口更改为抽象类时,它变得很有趣。错误消失。
总结警告发生的表格如下:
|----------------------------|------------------|
| Type | WARNING |
|----------------------------|------------------|
| interface with no defaults | NO |
|----------------------------|------------------|
| interface with defaults | YES |
|----------------------------|------------------|
| abstract class | NO |
|----------------------------|------------------|
Run Code Online (Sandbox Code Playgroud)
有什么原因还是只是一个错误?
java interface serializable compiler-warnings default-method
我理解如果一个类实现包含同名默认方法的多个接口,那么我们需要在子类中重写该方法,以便明确定义我的方法将执行的操作.
问题是,见下面的代码:
interface A {
default void print() {
System.out.println(" In interface A ");
}
}
interface B {
default String print() {
return "In interface B";
}
}
public class C implements A, B {
@Override
public String print() {
return "In class C";
}
public static void main(String arg[]) {
// Other funny things
}
}
Run Code Online (Sandbox Code Playgroud)
现在,接口A和B都有一个名为'print'的默认方法,但我想覆盖接口B的print方法 - 返回字符串并按原样保留A的打印方式.但是这段代码不能编译给出:
Overrides A.print
The return type is incompatible with A.print()
Run Code Online (Sandbox Code Playgroud)
很明显,编译器试图覆盖A的打印方法,我不明白为什么!
考虑以下代码:
interface A {
default void doA() {
System.out.println("a");
}
}
interface B {
void doB();
}
class Test implements A {
@Override
public void doA() {
// Works
B b = () -> A.super.doA();
b.doB();
// Does not compile
/*
new B() {
public void doB() {
A.super.doA();
}
}.doB();
*/
}
public static void main(String[] args) {
new Test().doA();
}
}
Run Code Online (Sandbox Code Playgroud)
这是做作,但基本上Test::doA()试图来包装this的B,并且具有B::doB()调用它的超强功能A.super.doA().
我可以打电话给A.super.doA()一个类型的lambda B就好了.但我无法弄清楚A.super.doA() …
default-method ×10
java ×9
java-8 ×8
interface ×4
inheritance ×1
kotlin ×1
lambda ×1
oop ×1
overriding ×1
serializable ×1
super ×1
testng ×1
type-erasure ×1