[英]What are the differences between abstract classes and interfaces in Java 8?
接口不能具有与之关联的状态。
抽象类可以具有与之关联的状态。
此外,不需要实现接口中的默认方法。 因此,通过这种方式,它不会破坏已有的代码,因为当接口确实接收到更新时,实现类不需要实现它。
因此,您可能会获得次优代码,但如果您想拥有更优化的代码,那么您的工作就是覆盖默认实现。
最后,如果出现菱形问题,编译器会发出警告, 您需要选择要实现的接口。
要显示有关钻石问题的更多信息,请考虑以下代码:
interface A {
void method();
}
interface B extends A {
@Override
default void method() {
System.out.println("B");
}
}
interface C extends A {
@Override
default void method() {
System.out.println("C");
}
}
interface D extends B, C {
}
这里我得到interface D extends B, C
的编译器错误interface D extends B, C
,表示:
interface D inherits unrelated defaults for method() form types B and C
修复是:
interface D extends B, C {
@Override
default void method() {
B.super.method();
}
}
如果我想从B
继承method()
。
如果D
是一个class
这同样适用。
要更多地了解Java 8中接口和抽象类之间的区别,请考虑以下Team
:
interface Player {
}
interface Team {
void addPlayer(Player player);
}
理论上,您可以提供addPlayer
的默认实现,以便您可以将玩家添加到例如玩家列表中。
可是等等...?
如何存储玩家列表?
答案是,即使您有可用的默认实现,也无法在界面中执行此操作。
已经有一些非常详细的解答,但他们似乎丢失了一个点,我至少认为是极少数理由之一,在所有有抽象类:
抽象类可以具有受保护的成员(以及具有默认可见性的成员)。 接口中的方法是隐式公共的 。
钻石问题的定义含糊不清。 多重继承可能会出现各种问题。 幸运的是,大多数都可以在编译时轻松检测到,编程语言支持简单的解决方案来解决这些问题。 大多数这些问题甚至不是钻石问题所特有的。 例如,没有钻石也可能发生冲突的方法定义:
interface Bar {
default int test() { return 42; }
}
interface Baz {
default int test() { return 6 * 9; }
}
class Foo implements Bar, Baz { }
钻石的具体问题是包容性与排他性的问题。 如果你有一个类型层次结构,其中B和C派生自A ,而D派生自B和C ,那么问题是:
好吧,在Java 8中,类型A必须是一个接口 。 所以没有区别,因为接口没有状态。 无关紧要, 接口可以定义默认方法 ,因为它们也没有状态。 他们可以调用直接访问状态的方法。 但是,这些方法总是基于单继承实现。
现在接口可以包含可执行代码,接口将接管许多用于抽象类的用例。 但抽象类仍然可以有成员变量,而接口则不能。
当两个接口为具有相同签名的相同方法提供默认实现时,通过简单地不允许类实现两个接口来避免钻石问题。
Java 8虽然引入了接口的默认实现,但这意味着它不再是接口和抽象类之间的关键区别。
仍有一些更为重要的差异。 参考这篇文章:
新的Java 8接口如何避免钻石问题?
案例1: 您正在实现两个具有相同default
方法的接口,您必须解决实现clas中的冲突
interface interfaceA{
default public void foo(){
System.out.println("InterfaceA foo");
}
}
interface interfaceB{
default public void foo(){
System.out.println("InterfaceB foo");
}
}
public class DiamondExample implements interfaceA,interfaceB{
public void foo(){
interfaceA.super.foo();
}
public static void main(String args[]){
new DiamondExample().foo();
}
}
以上示例产生以下输出:
InterfaceA foo
情况2: 您正在扩展基类并使用默认方法实现接口。 编译器会为您解决钻石问题,您无需像第一个示例那样解决它。
interface interfaceA{
default public void foo(){
System.out.println("InterfaceA foo");
}
}
class DiamondBase {
public void foo(){
System.out.println("Diamond base foo");
}
}
public class DiamondExample extends DiamondBase implements interfaceA{
public static void main(String args[]){
new DiamondExample().foo();
}
}
以上示例产生以下输出:
Diamond base foo
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.