问题描述
这里有一个简单的类来演示这个问题:
package com.mimvista.debug;
和
public class DefaultCollisionTest {
public static interface Interface1 {
public String getName();
}
public static interface Interface2 {
public default String getName(){returnMr. 2; };
}
public static< X extends Interface1& Interface2> String extractName(X target){
return target.getName();
Eclipse(Neon 2)很高兴地编译这个类,而javac (JDK 1.8.0_121)吐出以下编译错误:
$ javac src / com / mimvista / debug / DefaultCollisionTest.java
src\com\mimvista\debug\DefaultCollisionTest.java:13:error:class INT#1从类型Interface2和Interface1继承了getName()的抽象和默认值
public static< X扩展Interface1& Interface2>字符串extractName(X目标){
^
其中INT#1是交叉类型:
INT#1扩展Object,Interface1,Interface2
1错误
我相信Eclipse在这种情况下是正确的,但我并不完全确定。根据我对继承抽象和默认错误的理解,我认为它应该只在编译实现这两个接口的实际声明类时生成。看起来像javac可能会生成一个中间类来处理这个通用签名,并将其错误地进行默认的方法碰撞测试?
解决方案在中进行报告:
通过(见 I2>
< T extends IDefault>
,但是失败并且< T extends I1& IDefault>
和 javac :
接口I1 {
String get();
}
interface I2 {
String get();
}
interface IDefault {
default String get(){
returndefault;
};
}
public class Foo实现I1,I2,IDefault {
@Override
public String get(){
returnfoo ;
public static void main(String [] args){
System.out.print(getOf(new Foo()));
}
// static< T extends I1& IDefault> String getOf(T t){//失败,返回javac
static< T extends I1& I2> String getOf(T t){// OK
return t.get();
}
}
Here's a simple class that demonstrates the issue:
package com.mimvista.debug; public class DefaultCollisionTest { public static interface Interface1 { public String getName(); } public static interface Interface2 { public default String getName() { return "Mr. 2"; }; } public static <X extends Interface1&Interface2> String extractName(X target) { return target.getName(); } }
Eclipse (Neon 2) happily compiles this class while javac (JDK 1.8.0_121) spits out the following compile error:
$ javac src/com/mimvista/debug/DefaultCollisionTest.java src\com\mimvista\debug\DefaultCollisionTest.java:13: error: class INT#1 inherits abstract and default for getName() from types Interface2 and Interface1 public static <X extends Interface1&Interface2> String extractName(X target) { ^ where INT#1 is an intersection type: INT#1 extends Object,Interface1,Interface2 1 error
I believe that Eclipse is correct in this case but I'm not totally sure. Based on my understanding of the "inherits abstract and default" error, I think it should only be generated when compiling an actual declared class that implements those two interfaces. It seems like javac may be generating an intermediate class under-the-hood to deal with that generic signature and erroneously subjecting it to the default method collision test?
解决方案Eclipse is right.
I have not found this javac bug in the Java Bug Database and therefore reported it: JDK-8186643
Better explanation by Stephan Herrmann (see his comment below):
A class that implements multiple interfaces of the same method can be compiled with both compilers, even if the method of one interface has a default implementation. The class can be referenced as
<T extends I1 & I2>
as long as neither I1 nor I2 has a default implementation for a equally named method. Only if one of the two interfaces has a default implementation javac fails.In case of ambiguity which implementation should apply, the error should already occur when defining a class, not when the class is referred as
<T extends ...>
(see JLS 4.9. Intersection Types).See following example which works with
<T extends I1 & I2>
and<T extends IDefault>
, but fails with<T extends I1 & IDefault>
and javac:interface I1 { String get(); } interface I2 { String get(); } interface IDefault { default String get() { return "default"; }; } public class Foo implements I1, I2, IDefault { @Override public String get() { return "foo"; } public static void main(String[] args) { System.out.print(getOf(new Foo())); } // static <T extends I1 & IDefault> String getOf(T t) { // fails with javac static <T extends I1 & I2> String getOf(T t) { // OK return t.get(); } }
这篇关于Eclipse / javac在使用默认方法冲突编译签名时不同意;谁是对的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!