这是关于 Java 中使用参数化类型的签名方法的另一个问题。假设您有以下两种方法: static void f(List<Integer> l) {}
static void f(List<String> l) {}编译器会抱怨两种方法在类型擦除后具有相同的签名(两种参数类型都被擦除为仅List)。stackoverflow 上的许多类似问题都询问为什么会这样,但问题始终是关于实例(非静态)方法(例如,请参阅方法与类型中的另一个方法具有相同的擦除)。通常一半的答案基于以下(非常错误的)论点:编译器将删除字节码中的所有类型参数并使方法无法区分。好吧,只需打印字节码javap,您就会看到是否所有内容都被删除了!(虽然字节码丢失了大量参数化数据,但实际上保留了完整的方法签名,当您想要使用包含泛型类和方法的依赖项编译新类时,这绝对有用)。另一方面,最好的答案通常引用 JLS 8.4.2 并解释说,为了与旧的、预通用的 Java 版本(以及较新版本中的原始类型)兼容,禁止使用具有覆盖等效签名的方法。我同意后一个论点,但它只意味着实例方法(非静态),因为静态方法无论如何都不能被覆盖。静态方法可能有类似的解释,但我未能指出它。有人可以帮助我理解这一点吗?
1 回答
MYYA
TA贡献1868条经验 获得超4个赞
关于向后兼容性的争论仍然成立。
如果您有这段代码(不使用泛型,强烈建议不要使用,但即使在今天也是合法的,并且在应该仍然可以编译的 Java 1.4 代码中完全正常),编译器应该选择您的两种方法中的哪一种?
List rawList = new ArrayList(); YourClass.f(rawList);
更重要的是,假设您以某种方式选择两者之一,在生成的调用站点字节码中,泛型仍然会被删除,因此在运行时,JVM 不知道您指的是两者中的哪一个f(List)
。方法调用指定方法名称和签名,但该签名不包括泛型。这并不是出于兼容性问题。他们是否可以尝试使用带有扩展调用规范的新操作码之类的东西来更努力地推动这一点?或许。但现在就是这样。
另一方面,最好的答案通常引用 JLS 8.4.2 并解释说,为了与旧的、预通用的 Java 版本(以及较新版本中的原始类型)兼容,禁止使用具有覆盖等效签名的方法。
我同意后一个论点,但它只意味着实例方法(非静态),因为静态方法无论如何都不能被覆盖。
好吧,您不能覆盖静态方法,但是您的两个方法仍然是“覆盖等效的”,这意味着它们的签名非常接近,以至于您一次只能拥有其中一个(在子类情况下,一个如果因此而继承,则会覆盖另一个方法 --- 但这也意味着您不能在同一个类上拥有两个这样的方法)。
请注意,这不会造成任何实际问题,因为您始终可以通过更改为不同的方法名称来避免“重载”。
添加回答
举报
0/150
提交
取消