为什么void say(List< ? extends Number> list)
无法覆盖void say(List< Number> list)
。
尝试编译时会发生名称冲突。
答案 0 :(得分:5)
您无法覆盖声明为
的方法void say(List<? extends Number> list) // A
带
void say(List<Number> list) // B
仅仅是因为类型不相同。例如,List<Integer>
匹配List<? extends Number>
但不匹配List<Number>
,所以
List<Integer> integers = Arrays.<Integer>asList(1, 2, 3);
a.say(integers); // is valid assuming signature A
b.say(integers); // does not compile
(有关generics, wildcards, and type relationships)的详细信息,请参阅此问题。如果编译器允许您覆盖您想要的方式,则可以执行以下操作:
class A {
void say(List<? extends Number> numbers) { }
}
class B extends A {
void say(List<Number> numbers) { numbers.add(Double.valueOf(1.0)); }
}
List<Integer> onlyIntsPlease = new ArrayList<Integer>();
B b = new B();
// Oops! The list of `Integer` will now contain a `Double`...
b.say(onlyIntsPlease);
答案 1 :(得分:2)
这在一般理论上和由于Java Generics的细节都是不可能的。
一般原则是对于基类方法,重写方法必须是可替换的。例如,子类方法可以使用更宽的访问修饰符,但不能使用更窄的访问修饰符。在你的情况下,
void say(List<Number> list)
比
更具约束力void say(List<? extends Number> list)
所以这显然违反了可替代性原则。
一个实际的障碍是:覆盖是关于运行时多态,而泛型是关于编译时多态,并且实例的类型参数甚至不可用于方法调度机制。