为何代码`CustomerService service = ServiceFactory.getInstance().getServiceType(ServiceType.CUSTOMER);`未出现编译错误?
CustomerService service = ServiceFactory.getInstance().getServiceType(ServiceType.CUSTOMER);未出现编译错误? 哈哈,这个问题问得好,我来一步步给你拆解得明明白白:
1. 强制类型转换触发了「未检查转换」,绕过了编译检查
先看ServiceFactory里的getServiceType方法,你在switch分支里写了(T) new CustomerServiceImpl()这个强制转换。Java编译器在编译阶段,没办法确定CustomerServiceImpl实例能不能转换成推断出来的T类型(也就是你要赋值的CustomerService)——因为泛型在编译后会被擦除,编译器看不到运行时的实际类型匹配情况。
这种情况下,编译器不会直接报错,只会弹出一个**「未检查转换(unchecked cast)」的警告**。要是你没开IDE的全警告提示,可能压根没注意到这个提醒。这就好比你拍胸脯跟编译器说“我心里有数,你别管”,编译器就暂时放你一马,但运行时绝对会炸(抛出ClassCastException)——毕竟CustomerServiceImpl既没实现CustomerService,跟CustomerService半毛钱继承关系都没有。
2. 泛型约束的检查被强制转换弱化了
你的getServiceType方法声明了泛型约束<T extends SuperService>,按道理,当你把返回值赋值给CustomerService时,编译器必须检查CustomerService是不是SuperService的子类——但你的CustomerService根本没继承SuperService,这时候按理说该直接编译报错才对。
为啥没报错?还是拜那个强制转换所赐!编译器看到你手动做了(T)强制转换,就默认你已经搞定了类型兼容的问题,于是弱化了对泛型约束的严格检查,只通过警告来提醒你,而不是直接拦着你编译。
3. 编译器的类型推断逻辑在“帮倒忙”
当你写CustomerService service = ...时,编译器会自动推断泛型参数T就是CustomerService。这时候它本该验证CustomerService是否符合<T extends SuperService>的约束,但因为方法里的强制转换存在,编译器没办法在编译阶段验证这个转换的合法性,所以只能退而求其次,用警告代替错误。
最后给你指两条正路
其实你的代码藏着两个致命的类型不兼容问题:
CustomerService没继承SuperService,违反了getServiceType的泛型约束CustomerServiceImpl没实现CustomerService,根本不能给CustomerService的引用赋值
要解决这个问题,你只需要做两件事:
- 让
CustomerService继承SuperService:public interface CustomerService extends SuperService {...} - 让
CustomerServiceImpl实现CustomerService:public class CustomerServiceImpl implements CustomerService {...}
这样编译器就能正常做类型检查,既不会有警告,运行时也不会炸锅了。
备注:内容来源于stack exchange,提问作者Sonny Mad

