假设我有像这样的简单类
public interface Something{
public void doSomtehing()
}
class A{
public int getAVal(){
return 0;
}
}
class AWithSomething extends A implements Something{
public void doSomething{
//in fact do nothing, HAHA
}
}
abstract class B{
public abstract <T extends A & Something> T getAWithSomething()
}
class C extends B{
//allowed??? gives warnig about unchecked conversion
public A getAWithSomething {
return new A();
}
}
class D extends B{
//same unchecked warning
public AWithSomething getAWithSomething(){
return new AWithSomething();
}
}
C c = new C();
//not implemented but seems valid
c.getAWithSomething().doSomething();
D d = new D();
d.getAWithSomething().doSomething();
所以我的主要问题是:为什么编译器为什么允许类
C
仅返回A而不检查其是否在编译时实现了接口?编辑(由于达里扬的评论):
嗯,但我不允许这样声明:
class C extends B{
//not allowed!
public Something getAWithSomething {
return new Something(){
doSomething(){}
};
}
}
最佳答案
JLS将其称为migration compatibility。应该允许库实现者在不破坏客户端(B
)的情况下泛化其API(C
)。实际上,可以将B
替换为List
,将getAWithSomething()
替换为get(int)
,并使用自定义C
实现(例如apache commons List
)替换FixedSizeList
。
方法签名中的类型变量被擦除为原始类或接口类型。 T
中的类型变量B.getAWithSomething()
被擦除到其最左侧的A
。迁移兼容性基于生成的方法签名A getAWithSomething()
。这意味着重写getAWithSomething()
的子类必须声明A
的返回类型或其子类型。
请注意,您会收到一条警告,提示“小心,您正在将A
传递为A&Something
,这可能会出错”。它可以:在返回的doSomething()
上调用A
将抛出一个ClassCastException
,因为A
无法转换为Something
。