java的默认值规则
随着Java 8中默认方法的引入,一个类现在可以从多个位置(例如另一个类或接口)继承相同的方法。 在这种情况下,可以使用以下规则来确定选择哪种方法:
- 类或超类方法声明始终优先于默认方法
- 否则,将使用具有最具体的默认提供接口的方法
- 最后,如果方法同样特定,则会出现编译器错误,并且您将被迫显式覆盖该方法并指定您的类应调用的方法
让我们看一些示例并应用这些规则。
范例1:
以下代码显示什么?
public interface A {default void name() {System.out.println("A");}
}public interface B {default void name() {System.out.println("B");}
}public class C implements A {@Overridepublic void name() {System.out.println("C");}
}public class D extends C implements A, B {public static void main(final String... args) {new D().name();}
}
答案 :C
这是因为,如规则1所述,超类C
的name()
方法声明优先于A
和B
的默认方法声明。
范例2:
以下代码显示什么?
public interface A {default void name() {System.out.println("A");}
}public interface B extends A {@Overridedefault void name() {System.out.println("B");}
}public class C implements A {}public class D extends C implements A, B {public static void main(final String... args) {new D().name();}
}
答案 :B
不同于前面的例子, C
不覆盖name()
但由于它实现A
,它具有从默认方法A
。 根据规则2,如果类或超类中没有方法,则选择最特定的默认提供接口。 因为B
扩展了A
,所以它更加具体,因此打印了“ B”。
范例3:
以下代码显示什么?
public interface A {default void name() {System.out.println("A");}
}public interface B {default void name() {System.out.println("B");}
}public class D implements A, B {public static void main(final String... args) {new D().name();}
}
答 :编译器错误! Duplicate default methods named name with the parameters () and () are inherited from the types B and A
在此示例中,没有更多特定的默认提供接口可供选择,因此编译器将引发错误。 要解决该错误,您需要显式重写D
的方法,并指定要D
使用的方法声明。 例如,如果要使用B
:
class D implements A, B {@Overridepublic void name() {B.super.name();}
}
范例4:
以下代码显示什么?
public interface A {default void name() {System.out.println("A");}
}public interface B extends A {}public interface C extends A {}public class D implements B, C {public static void main(final String... args) {new D().name();}
}
答 :A
子接口B
和C
并未覆盖该方法,因此实际上只有A
的方法可供选择。 附带说明一下,如果B
或C
(但不是全部)都覆盖了该方法,则将应用规则2。 顺便说一句,这是钻石问题 。
翻译自: https://www.javacodegeeks.com/2016/06/java-8-default-method-resolution-rules.html
java的默认值规则