鉴于Java 8,为什么下面的代码无法编译?
interface Father {
static void method() { }
}
interface Mother {
default void method() { }
}
interface Child extends Father, Mother {
static void method() { }
}
据我了解,每个静态方法都属于其特定的类,因此,为什么当Child接口定义static void method() { }
时,编译器会出现以下错误?
儿童中的method()与母亲中的method()冲突的方法是静态的
Child不应保留Mother的默认方法实现,而允许父亲和Child拥有自己的静态方法,例如: Father.method()和Child.method()吗?
答案 0 :(得分:4)
Father
在这里不是问题,因为接口的静态方法是不继承的 (例如List.of(..)
不能通过{ {1}}),因此没有覆盖/隐藏,也就意味着没有冲突。
因此,我们可以放心地写
ArrayList.of(..)
问题是来自interface Father {
static void method() { }
}
interface Child extends Father {
static void method() { }
}
接口的default void method() { }
方法,该方法继承到Mother
,这意味着在
Child
您最终将获得具有两个interface Child extends Father, Mother {
static void method() { }
}
版本的接口:静态和非静态(默认)
method()
但是为什么会出现问题?
想象一下您想向interface Child extends Father, Mother {
static void method() { }
default void method() { } //inherited from Mother
}
接口添加另一个方法,该方法将调用Child
method()
应该从 static method()还是从 default method()执行代码?编译器将无法决定。
尽管可以使用
解决此情况interface Child extends Father, Mother {
static void method() { }
default void method() { } //inherited from Mother
default void demo(){
method(); //which code block should be executed?
}
}
(用于静态方法)Child.method()
作为默认方法(是的,它不会造成歧义,因为静态方法不会被this.method()
是实例的类继承),首先是要防止此类问题。这就是为什么我们必须在一处(定义或继承)中不要使用具有相同签名(名称+ parameterTypes)的静态和非静态方法的原因。
答案 1 :(得分:1)
这是一个有趣的情况。我认为简单的答案是,从未允许静态方法在基类中隐藏(它们不能覆盖)非静态方法。如果您从static
中删除Father
修饰符,这也将导致Child无法编译。这可能是为了避免混淆。
因此默认方法仅遵循该现有规则。
“但请稍等”,您可能会想,“添加了默认方法,其明确意图是允许库开发人员在不破坏现有代码的情况下将新功能引入旧接口。如果任何现有代码具有名称冲突的静态方法,不会破吗?”
实际上,我认为不是。 IIRC,这是故意允许二进制兼容性和源兼容性不同的地方。我认为您会发现以下情况:
interface Child
(以及使用它的东西)已经被编译,而interface Mother
中没有该默认方法,并且interface Mother
中添加了默认方法,并仅仅编译了该源文件。 然后,我认为您给出的代码可以正常工作(在字节码/ JVM级别)。但是,在尝试对更新的interface Child
进行重新编译 interface Mother
时,它会在编译时中断。
答案 2 :(得分:0)