Java 泛型 - 方法覆盖
Java Generics - Method overriding
我有一对 类 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){}
}
我有两个问题。
[问题一]
我说的对吗,case2 是 case1 的运行时表示(类型擦除后)?
[q2]
如果我对 [q1] 的看法是正确的,那么为什么 case1 被接受为有效的覆盖? (我知道为什么 case2 不是有效的覆盖,因为参数不一样。)
有人请阐明这一点。
提前致谢。
[q1] 的答案是否定的。
编译器将在 ClassB
中生成一个 bridge 方法,该方法实际上会覆盖 method(Number)
.
class ClassB extends ClassA{
// bridge method
void method(Number i){
method((Integer)i);
}
void method(Integer i){}
}
您将在java doc类型擦除中获得完整答案。
ClassB
的实际超类是 ClassA<Integer>
。因此其成员函数 method
具有编译时签名:
void method(Integer t){}
你可以通过调用类似
的东西来说服自己
ClassA a = new ClassB();
a.method(1.0);
您应该会看到一个运行时错误。实际上只能这样编译,因为我用的是擦除版的ClassA
。事实上,每一个分配给
ClassA<Integer>
以外的泛型类型(例如 ClassA<Number
>)将因类型不兼容而失败。
在 Java 中(从版本 5 开始)return 重写方法的类型必须是协变的,并且重写方法的参数必须是逆变的。
这意味着覆盖 class 的内容可以更具体 return 并且可以接受的内容更多。
在您的第二个示例中,想象一个类型为 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
定义的合同。
我有一对 类 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){}
}
我有两个问题。
[问题一]
我说的对吗,case2 是 case1 的运行时表示(类型擦除后)?
[q2] 如果我对 [q1] 的看法是正确的,那么为什么 case1 被接受为有效的覆盖? (我知道为什么 case2 不是有效的覆盖,因为参数不一样。)
有人请阐明这一点。 提前致谢。
[q1] 的答案是否定的。
编译器将在 ClassB
中生成一个 bridge 方法,该方法实际上会覆盖 method(Number)
.
class ClassB extends ClassA{
// bridge method
void method(Number i){
method((Integer)i);
}
void method(Integer i){}
}
您将在java doc类型擦除中获得完整答案。
ClassB
的实际超类是 ClassA<Integer>
。因此其成员函数 method
具有编译时签名:
void method(Integer t){}
你可以通过调用类似
的东西来说服自己ClassA a = new ClassB();
a.method(1.0);
您应该会看到一个运行时错误。实际上只能这样编译,因为我用的是擦除版的ClassA
。事实上,每一个分配给
ClassA<Integer>
以外的泛型类型(例如 ClassA<Number
>)将因类型不兼容而失败。
在 Java 中(从版本 5 开始)return 重写方法的类型必须是协变的,并且重写方法的参数必须是逆变的。
这意味着覆盖 class 的内容可以更具体 return 并且可以接受的内容更多。
在您的第二个示例中,想象一个类型为 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
定义的合同。