【发布时间】:2013-08-12 11:49:31
【问题描述】:
为什么void say(List< ? extends Number> list) 不能被void say(List< Number> list) 覆盖。
尝试编译时会发生名称冲突。
【问题讨论】:
-
使用哪种编程语言?
为什么void say(List< ? extends Number> list) 不能被void say(List< Number> list) 覆盖。
尝试编译时会发生名称冲突。
【问题讨论】:
您不能覆盖声明为
的方法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);
【讨论】:
这在一般理论基础和 Java 泛型的特殊性上都是不可能的。
一般原则是覆盖方法必须可替换基类方法。例如,子类方法可以使用 wider 访问修饰符,但不能使用 narrower 访问修饰符。在你的情况下,
void say(List<Number> list)
比
更具约束力void say(List<? extends Number> list)
所以这显然违反了可替代性原则。
一个实际的障碍是:重写是关于 runtime 多态性,而泛型是关于 compile-time 多态性,并且实例的类型参数甚至对方法分派机制。
【讨论】: