Java重写方法时为何不能新增类型参数?有什么更优实现方案?
问题1:为什么给重写方法新增类型参数会导致无法重写父类非泛型方法
这是Java语言规范(JLS)明确规定的重写校验规则:子类方法要构成重写,方法的类型参数列表必须和父类被重写方法的类型参数列表完全一致。
父类Foo的foo()没有声明任何类型参数,子类Bar给foo()新增了<T>类型参数,相当于两个方法的签名在类型擦除前就不匹配,自然不构成重写关系。至于两者擦除后签名一致,只会触发编译器的方法冲突报错,不会被判定为重写。
之所以设计这条规则,是为了保证泛型体系的一致性:父类方法的签名是对外的契约,如果允许子类随意给方法加类型参数,会导致父类引用调用方法时的泛型约束逻辑和子类实现不一致,破坏多态的安全性。
问题2:更优的实现方案
分两种场景给出方案:
方案1:可以修改父类Foo的定义
最合理的做法是把泛型约束上移到父类,从根源解决问题:
// 父类增加泛型声明 abstract class Foo<T> { public abstract void foo(); } class Bar<T> extends Foo<T> { private Map<T, List<T>> getStuff() { ... } @Override public void foo() { Map<T, List<T>> stuff = getStuff(); for (Map.Entry<T, List<T>> e : stuff.entrySet()) { T key = e.getKey(); List<T> lst = e.getValue(); lst.add(key); } } }
这种方案完全符合泛型规范,没有任何额外开销和警告,是最推荐的做法。
方案2:无法修改父类Foo的定义
你目前用的拆分方法已经是类型安全、无警告的标准实现,几乎没有优化空间。如果追求代码更简洁,可以用安全的类型强转,只要你能确定getStuff()返回的Map一定满足「key的类型和对应value List的元素类型一致」的约束:
@Override @SuppressWarnings("unchecked") public void foo() { // 这个强转是安全的,因为getStuff的返回本身就是Map<T, List<T>> Map<Object, List<Object>> stuff = (Map<Object, List<Object>>) getStuff(); for (Map.Entry<Object, List<Object>> e : stuff.entrySet()) { Object key = e.getKey(); List<Object> lst = e.getValue(); lst.add(key); } }
这种方案不需要拆分方法,代码更紧凑,只要业务逻辑保证强转的安全性,就可以正常使用。
内容的提问来源于stack exchange,提问作者Dragon
相关产品推荐
相关产品推荐

