为何未实现Interface的Concrete类可赋值给有上界约束的泛型方法返回值?
问题原因解答
1. 原始代码可以正常编译的原因
Java泛型方法调用时会触发目标类型推断:当方法返回值直接赋值给指定类型的变量时,编译器会以目标变量类型为约束,推导泛型参数T的合法取值。
对于你的代码,编译器推导T的目标类型为交叉类型 Concrete & Interface:
- 满足泛型方法声明的上界约束
T extends Interface - 可以赋值给左侧的
Concrete类型变量
Java编译器不会全局校验是否真的存在类同时实现Interface和继承Concrete,只要语法层面交叉类型合法,推断就会通过。同时null可以转型为任意引用类型,所以返回null的版本不会有任何编译问题。
如果你的Concrete类被声明为final,编译器就会判定不存在同时满足两个约束的类型,原始代码也会直接编译失败。
如果你手动指定泛型参数类型,编译也会直接失败,比如调用写为:
Concrete c = Main.<Concrete>foo();
此时编译器会直接检查Concrete是否满足extends Interface的约束,因为不满足就会报编译错误。
2. 修改返回值后仅报unchecked警告、运行时报错的原因
- 编译阶段:泛型会执行类型擦除,T的上界是
Interface,所以(T) new Interface(){}的强制转型会被擦除为(Interface),而你创建的匿名类本身就是Interface的实现,语法合法。但编译器无法确认这个转型一定符合运行时实际的T类型,所以只会给出unchecked cast的警告,不会阻断编译。 - 调用处无警告:编译器完成类型推断后,会自动在
Concrete c = foo()的赋值位置隐式插入Concrete类型的强制转型,这部分逻辑对开发者不可见,所以调用行不会有警告。 - 运行时报错:实际运行时,foo返回的是
Interface匿名实现类的实例,和Concrete没有继承/实现关系,隐式插入的强制转型失败,就会抛出ClassCastException。
内容的提问来源于stack exchange,提问作者Bernardo Rufino
相关产品推荐
相关产品推荐

