6

乍一看,我认为以下是有道理的:

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呢?

4

2 回答 2

13

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);
    }
}

注意:SyntheticandBridge不是真正的注释,但编译后的类文件确实将这些方法标记为“合成”和“桥接”。

通过使用这些桥接方法,Java 确保如果你有一个Impl,你可以调用Impl#getValue(Integer)Integer(如果你知道它实际上有 type Impl),或者你可以调用“通用” Test#getValue(Object)Object,如果你只知道它是一个Test<?>.

于 2020-07-25T01:12:24.073 回答
0

这里有一种思维方式可以帮助您更多地了解泛型:将泛型视为严格的编译时保护。这种保护在运行时不存在(它是擦除的上下文)。为什么泛型必须这样做?支持 Java 5 之前的遗留代码。

编译器使用泛型类型信息(<Integer>在您的Test类中)来确保您的代码不会将错误的东西放入您的getValue()方法中,而不是 String,不是 Float,不是 Double,只有 Integer。因此,泛型为您提供编译时保护和运行时保护。

于 2020-07-25T01:47:54.757 回答