我有一对班级ClassA& ClassB如下所示。
案例1:
class ClassA<T extends Number>{
void method(T t){}
}
class ClassB extends ClassA<Integer>{
@Override
void method(Integer i){}
}
案例2:
class ClassA{
void method(Number t){}
}
class ClassB extends ClassA{
@Override
void method(Integer i){}
}
我这里有两个问题 [Q1] 我说对了,case2是case1的运行时表示(在类型擦除之后)?
[Q2] 如果我对[q1]是正确的,那么为什么case1被接受为有效覆盖? (我知道为什么case2不是有效覆盖,因为参数不相同。)
有人请对此有所了解。 提前谢谢。
答案 0 :(得分:19)
[q1]的答案是否定的。
编译器将在ClassB
中生成实际上覆盖method(Number)
的 bridge 方法。
class ClassB extends ClassA{
// bridge method
void method(Number i){
method((Integer)i);
}
void method(Integer i){}
}
您将在java doc类型擦除中获得完整的答案。
答案 1 :(得分:1)
在Java中(从版本5开始),重写方法的返回类型必须是协变的,并且重写方法的参数必须是逆变的。
这意味着覆盖类可以更具体地返回它所接收的内容,并且更接受它所接收的内容。
在您的第二个示例中,假设ClassA
类型的变量,其中ClassB
的实例为值。
ClassA a = new ClassB(); // This is legal, since ClassB is a subclass of ClassA
a.method(1.0); // This is legal, since ClassA.method accepts Number
然而另一种方式是可以的:
public class ClassC { public Number method(Integer i) {...} }
public class ClassD extends ClassC {
@Override
public Integer method(Number n) {...}
}
有效,因为ClassD
仍然符合ClassC
定义的合同。
答案 2 :(得分:0)
ClassB
的实际超类是ClassA<Integer>
。因此,其成员函数method
具有编译时签名:
void method(Integer t){}
你可以通过调用类似
之类的东西来说服自己ClassA a = new ClassB();
a.method(1.0);
您应该会看到运行时错误。实际上只能编译它,因为我使用了ClassA
的擦除版本。实际上每个任务都分配到了
ClassA<Integer>
以外的泛型类型(例如ClassA<Number
&gt;)会因类型不兼容而失败。