Java 中类型擦除后具有相同签名的静态方法

Static methods with same signature after type erasure in Java

这是关于在 Java 中使用参数化类型的签名方法的另一个问题。

假设你有以下两种方法:

    static void f(List<Integer> l) {}
    static void f(List<String> l) {}

编译器会抱怨两种方法在类型擦除后具有相同的签名(两种参数类型都被擦除为 List)。

关于 Whosebug 的许多类似问题都会问为什么会这样,但问题总是关于实例(非静态)方法(例如参见 [​​=14=])。

通常一半的答案是基于以下(非常错误的)论点:编译器会清除字节码中的所有类型参数并使方法无法区分。好吧,只需打印带有 javap 的字节码,您就会看到是否所有内容都被删除了! (虽然字节码丢失了很多参数化数据,但实际上保留了完整的方法签名,当你想使用包含通用 classes 和方法的依赖项编译新的 class 时,这绝对有用)。 =15=]

另一方面,最好的答案通常引用 JLS 8.4.2 并解释说,为了与旧的、前通用的 Java 版本(以及较新版本中的原始类型)兼容,覆盖的方法-禁止等效签名。

我同意后一个论点,除了它只对实例方法(非静态)有意义,因为无论如何都不能覆盖静态方法。

静态方法可能有类似的解释,但我没能准确指出。有人可以帮助我理解这一点吗?

向后兼容的论点仍然成立。

如果你有这段代码(不使用泛型,强烈建议不要使用,但即使在今天也是合法的,并且在应该仍然可以编译的 Java 1.4 代码中完全正常),编译器应该使用你的两种方法中的哪一种选择?

List rawList = new ArrayList();
YourClass.f(rawList);

更重要的是,假设您以某种方式选择两者之一,在生成的调用站点字节码中,泛型仍然被删除,因此在运行时,JVM 不知道两者中的哪一个 f(List) 你的意思是。方法调用指定方法名称和签名,但该签名不包括泛型。那不是由于兼容性问题。他们是否可以尝试使用具有扩展调用规范的新操作码之类的东西来更加努力地推动这一点?可能是。但是现在就是这样了。

On the other hand, the best answers usually quote JLS 8.4.2 and explain that, for compatibility with old, pre-generic, Java versions (and raw types in newer versions), methods with override-equivalent signatures are forbidden.

I am ok with the latter argument, except it only means something for instance methods (non static), as static methods cannot be overridden anyway.

好吧,你不能覆盖静态方法,但你的两个方法仍然是“覆盖等效的”,这意味着它们的签名彼此非常接近,以至于你一次只能使用其中一个(在一个 subclass 情况,如果继承,一个会覆盖另一个 --- 但这也意味着你不能在同一个 class).

上使用两个这样的方法

请注意,这不会造成任何实际问题,因为您始终可以通过更改为不同的方法名称来避免“重载”的需要。