为什么擦除仍然允许overriding/implementation?
Why does erasure still allow overriding/implementation?
乍一看,我认为以下内容是有道理的:
interface Test<T> {
T getValue(T n);
}
class Impl implements Test<Integer>{
public Integer getValue(Integer n){
return n;
}
}
它编译正确所以一切看起来都很好。
但后来我又考虑了一些,在擦除的上下文中,在我看来,测试接口被擦除为:
interface Test {
Object getValue(Object n);
}
那么Impl怎么还能实现Test呢?
javac
实际上为此创建桥接方法:
class Impl implements Test<Integer>{
@Override public Integer getValue(Integer n){
return n;
}
}
编译为
class Impl implements Test {
public Integer getValue(Integer n) { // overrides nothing!
return n;
}
@Override @Synthetic @Bridge public Object getValue(Object n) {
return this.getValue((Integer)n);
}
}
注意:Synthetic
和 Bridge
不是真正的注释,但编译的 class 文件确实将这些方法标记为“合成”和“桥接”。
通过使用这些桥接方法,Java 确保如果你有一个 Impl
,你可以调用 Impl#getValue(Integer)Integer
(如果你知道它实际上有类型 Impl
),或者如果您只知道它是 Test<?>
.
,则可以调用“通用”Test#getValue(Object)Object
这里有一种思维方式可以帮助您更多地了解泛型:将泛型视为一种严格的编译时保护。 None 这种保护在运行时存在(它是擦除的上下文)。为什么仿制药必须这样做?支持Java之前的旧代码 5.
编译器使用通用类型信息(<Integer>
在您的 Test
class 中)以确保您的代码不会将错误的东西放入您的 getValue()
方法,不是 String,不是 Float,不是 Double,只有 Integer。因此,泛型同时为您提供编译时保护和运行时保护。
乍一看,我认为以下内容是有道理的:
interface Test<T> {
T getValue(T n);
}
class Impl implements Test<Integer>{
public Integer getValue(Integer n){
return n;
}
}
它编译正确所以一切看起来都很好。
但后来我又考虑了一些,在擦除的上下文中,在我看来,测试接口被擦除为:
interface Test {
Object getValue(Object n);
}
那么Impl怎么还能实现Test呢?
javac
实际上为此创建桥接方法:
class Impl implements Test<Integer>{
@Override public Integer getValue(Integer n){
return n;
}
}
编译为
class Impl implements Test {
public Integer getValue(Integer n) { // overrides nothing!
return n;
}
@Override @Synthetic @Bridge public Object getValue(Object n) {
return this.getValue((Integer)n);
}
}
注意:Synthetic
和 Bridge
不是真正的注释,但编译的 class 文件确实将这些方法标记为“合成”和“桥接”。
通过使用这些桥接方法,Java 确保如果你有一个 Impl
,你可以调用 Impl#getValue(Integer)Integer
(如果你知道它实际上有类型 Impl
),或者如果您只知道它是 Test<?>
.
Test#getValue(Object)Object
这里有一种思维方式可以帮助您更多地了解泛型:将泛型视为一种严格的编译时保护。 None 这种保护在运行时存在(它是擦除的上下文)。为什么仿制药必须这样做?支持Java之前的旧代码 5.
编译器使用通用类型信息(<Integer>
在您的 Test
class 中)以确保您的代码不会将错误的东西放入您的 getValue()
方法,不是 String,不是 Float,不是 Double,只有 Integer。因此,泛型同时为您提供编译时保护和运行时保护。