抽象超类的默认接口方法
Default interface method for abstract superclass
假设我有以下结构:
abstract class A {
abstract boolean foo();
}
interface B {
default boolean foo() { return doBlah(); }
}
class C extends A implements B {
//function foo
}
Java 现在会抱怨 class C
必须从 A
实现抽象方法 foo。
我可以通过重新定义 C
中的函数并简单地调用 B.super.foo();
.
来相对容易地解决这个问题
但是我不明白为什么接口 B
的默认函数本身不能满足这个要求,我想更好地了解 java 的底层机制。
在程序的当前状态下,如果要在 C.java
中覆盖 A#foo
(其中默认方法 returns true
和覆盖方法 returns false
,打印 C#foo
将导致 false
,完全忽略默认方法。
抽象 class 中定义的任何抽象方法都需要被扩展抽象 class 的第一个具体 class 覆盖。为此,需要 C.java
覆盖 A#foo
.
不需要覆盖接口中的默认方法。
但是,这两种方法共享相同的签名,这意味着一个方法需要被覆盖,另一个可以被覆盖。
这是一个非常糟糕的设计,不应使用,因为共享相同签名的方法不能同时被覆盖。如果您希望被要求覆盖抽象方法,则只需将抽象方法或默认方法的名称更改为 foo
.
以外的名称
abstract class A {
abstract boolean bar();
}
interface B {
default boolean foo() { return doBlah(); }
}
class C extends A implements B {
@Override
public boolean foo() {
...
}
@Override
public boolean bar() {
...
}
}
如果您只想在某些情况下重写 A#foo
,那么您可以简单地完全删除抽象方法并保留 B.java
中的默认方法,并在 [=14] 中重写它=]:
abstract class A {
}
interface B {
default boolean foo() { return doBlah(); }
}
class C extends A implements B {
@Override
public boolean foo() {
...
}
}
如果删除 A#foo
不是一个选项,则将默认方法 B#foo
重命名为其他名称。
abstract class A {
abstract boolean foo();
}
interface B {
default boolean bar() { return doBlah(); }
}
class C extends A implements B {
@Override
public boolean foo() {
...
}
@Override
public boolean bar() {
...
}
}
的回答启发了我想出这个解决方案:
interface Z {
abstract boolean foo();
}
abstract class A implements Z {
}
interface B extends Z {
default boolean foo() { return doBlah(); }
}
class C extends A implements B {
}
这样 class A
的所有子 class 都需要定义一个方法 foo()
,而不需要每个 class 实现 B
重新实现它。
接口中的默认方法用于防止在向接口添加方法时破坏依赖于接口的程序。
在您描述的情况下,尚不清楚接口中的默认方法(按设计必须在 稍后 添加)是否真正履行了最初设想的合同摘要 Class.
在这种情况下Java投诉比较安全
以上文字是我对9.4.1.3 of the JLS SE8 spec中的一段话的解读,我引用:
Similarly, when an abstract and a default method with matching signatures are inherited, we produce an error. In this case, it would be possible to give priority to one or the other - perhaps we would assume that the default method provides a reasonable implementation for the abstract method, too. But this is risky, since other than the coincidental name and signature, we have no reason to believe that the default method behaves consistently with the abstract method's contract - the default method may not have even existed when the subinterface was originally developed. It is safer in this situation to ask the user to actively assert that the default implementation is appropriate (via an overriding declaration).
假设我有以下结构:
abstract class A {
abstract boolean foo();
}
interface B {
default boolean foo() { return doBlah(); }
}
class C extends A implements B {
//function foo
}
Java 现在会抱怨 class C
必须从 A
实现抽象方法 foo。
我可以通过重新定义 C
中的函数并简单地调用 B.super.foo();
.
但是我不明白为什么接口 B
的默认函数本身不能满足这个要求,我想更好地了解 java 的底层机制。
在程序的当前状态下,如果要在 C.java
中覆盖 A#foo
(其中默认方法 returns true
和覆盖方法 returns false
,打印 C#foo
将导致 false
,完全忽略默认方法。
抽象 class 中定义的任何抽象方法都需要被扩展抽象 class 的第一个具体 class 覆盖。为此,需要 C.java
覆盖 A#foo
.
不需要覆盖接口中的默认方法。
但是,这两种方法共享相同的签名,这意味着一个方法需要被覆盖,另一个可以被覆盖。
这是一个非常糟糕的设计,不应使用,因为共享相同签名的方法不能同时被覆盖。如果您希望被要求覆盖抽象方法,则只需将抽象方法或默认方法的名称更改为 foo
.
abstract class A {
abstract boolean bar();
}
interface B {
default boolean foo() { return doBlah(); }
}
class C extends A implements B {
@Override
public boolean foo() {
...
}
@Override
public boolean bar() {
...
}
}
如果您只想在某些情况下重写 A#foo
,那么您可以简单地完全删除抽象方法并保留 B.java
中的默认方法,并在 [=14] 中重写它=]:
abstract class A {
}
interface B {
default boolean foo() { return doBlah(); }
}
class C extends A implements B {
@Override
public boolean foo() {
...
}
}
如果删除 A#foo
不是一个选项,则将默认方法 B#foo
重命名为其他名称。
abstract class A {
abstract boolean foo();
}
interface B {
default boolean bar() { return doBlah(); }
}
class C extends A implements B {
@Override
public boolean foo() {
...
}
@Override
public boolean bar() {
...
}
}
interface Z {
abstract boolean foo();
}
abstract class A implements Z {
}
interface B extends Z {
default boolean foo() { return doBlah(); }
}
class C extends A implements B {
}
这样 class A
的所有子 class 都需要定义一个方法 foo()
,而不需要每个 class 实现 B
重新实现它。
接口中的默认方法用于防止在向接口添加方法时破坏依赖于接口的程序。
在您描述的情况下,尚不清楚接口中的默认方法(按设计必须在 稍后 添加)是否真正履行了最初设想的合同摘要 Class.
在这种情况下Java投诉比较安全
以上文字是我对9.4.1.3 of the JLS SE8 spec中的一段话的解读,我引用:
Similarly, when an abstract and a default method with matching signatures are inherited, we produce an error. In this case, it would be possible to give priority to one or the other - perhaps we would assume that the default method provides a reasonable implementation for the abstract method, too. But this is risky, since other than the coincidental name and signature, we have no reason to believe that the default method behaves consistently with the abstract method's contract - the default method may not have even existed when the subinterface was originally developed. It is safer in this situation to ask the user to actively assert that the default implementation is appropriate (via an overriding declaration).