我试图理解为什么编译器不会在下面的代码中打印编译时错误。它编译,但显然不会工作。
有人知道编译器允许它的原因吗?
public class Tests {
public static void main(String... args){
// Lines below are acceptable for the compiler and work well in runtime.
GenericClass<FooClassWithFooInterface> genericClass1 = new GenericClass();
genericClass1.print(new FooClassWithFooInterface());
// Lines below are oddly acceptable for the compiler and, obviously, won't work in runtime.
GenericClass genericClass2 = new GenericClass();
genericClass2.print(new FooClassWithFooInterface());
genericClass2.print(new FooClass()); // why the compiler not throw a compile-time error?
}
}
class GenericClass<T extends FooClass & FooInterface>{
public void print(T t){
t.fooMethod();
}
}
class FooClass{
}
interface FooInterface{
public void fooMethod();
}
class FooClassWithFooInterface extends FooClass implements FooInterface{
@Override
public void fooMethod() {
System.out.println("foo");
}
}
控制台输出:
foo
foo
Exception in thread "main" java.lang.ClassCastException: FooClass cannot be cast to FooInterface
at GenericClass.print(Tests.java:18)
at Tests.main(Tests.java:11)
我创建了fooMethod()只是为了强制这个运行时错误。
我认为编译器可以检查new FooClass()
是否与<? extends FooClass & FooInterface>
不匹配并强制编译错误。
如果我们将GenericClass更改为T extends FooClassWithFooInterface
而不是T extends FooClass & FooInterface
,编译器最终会显示编译时错误:
class GenericClass<T extends FooClassWithFooInterface>{
public void print(T t){
t.fooMethod();
}
}
中未发现与此问题相关的任何限制
答案 0 :(得分:0)
当您使用多个边界时,在编译时类型擦除之后,第一个边界将保留在类型签名中。根据需要为后续边界插入强制转换。所以,如果您要查看已编译的GenericClass
,您会看到类似
class GenericClass {
public void print(FooClass t){
((FooInterface) t).fooMethod();
}
}
因为编译器发现GenericClass
具有print(FooClass)
方法,所以它不会抱怨。但是在运行时,方法内部的强制转换失败了。
为什么编译器允许这样做,当一个人可以推断这必然会失败?好吧,编译器并不像你那么聪明。当你将自己局限于类型安全代码时,它只能找到问题,这意味着永远不要使用原始类型或抑制类型警告。
还有一些其他情况,一个人,看着上下文,可以推断其他操作是安全的,但编译器会抱怨。编译器只使用声明的信息,一次查看一个表达式;它不考虑泛型类型的整个上下文。
答案 1 :(得分:0)
您明确告诉编译器不在此处检查类型:
GenericClass genericClass2 = new GenericClass();
通过省略泛型类型参数,您将强制编译器进入遗留模式(其中为java prioer编写的代码使用JDK5 +进行5次编译)。如果没有给出泛型类型参数,则会得到警告,并且编译器接受泛型类型的任何类型。
所以基本上你是在拍摄自己的脚,现在抱怨编译器没有阻止你,明确告诉他闭嘴后:)