鉴于以下情况:
interface Base { }
interface Derived extends Base{ }
interface OtherDerived extends Base{ }
class A {
void implementation(Derived stuff) {
// Implementation A
}
}
class B extends A {
// contravariant; does not override
void implementation(Base stuff) {
// Implementation B
}
}
此代码中的方法调用将按如下方式调度:
(new B()).implementation(derivedObject); // Ex. 1: calls A.implementation
(new B()).implementation(baseObject); // Ex. 1: calls B.implementation
(new B()).implementation(otherDerivedObject()); // Ex. 2: calls B.implementation
我一直想知道的是,为什么Java将逆变方法(B.implementation)基本上视为一个重载(除了A.implementation和B.implementation的签名不是覆盖等价的)。有没有一个故意的理由来调度最具体的方法签名(如果是这样,你会指出我在Java规范中明确指出的那些地方吗?),或者它只是在Java中如何实现重写的偶然结果?
答案 0 :(得分:1)
Java会从其父级继承所有方法,除非它们已被覆盖或隐藏。这意味着您的B
类与
class A {
void implementation(Derived stuff) {
// Implementation A
}
}
class B extends A {
// contravariant; does not override
void implementation(Base stuff) {
// Implementation B
}
void implementation(Derived stuff) {
super.implementation(stuff);
}
}
这样做的好处就是说你有
class A {
void implementation(Derived stuff) {
// Implementation A
}
}
class B extends A {
}
和
new B().implementation(new Derived());
如果稍后将方法添加到B提供向后兼容性,则此编译代码不会更改它的行为。
答案 1 :(得分:0)
首先,您可能看起来应该能够覆盖一个方法并接受更多一般参数(类似于您可以覆盖一个方法并返回更多特定类型的事实)。
然而,它会给语言带来很大的复杂性。例如,
class A {
void foo(String s) {}
}
class B extends A {
void foo(CharSequence s) { System.out.println(true); }
void foo(Serializable s) { System.out.println(false); }
}
根据你的提议,这应该打印什么?
A a = new B();
a.foo("bar");
所以规则就是为了覆盖一个方法,你必须拥有相同的参数列表。 (在某些情况下,当参数列表不相同但具有相同的擦除时,您可以覆盖)。给出了精确的定义here。