两个方法都有相同的擦除,但都不覆盖对方



我有这样的代码:

class A {
public void func(String str, List<String> lst) {}
}
class B extends A {
public void func(String str, List<Integer> lst) {}  // Does not compile
}

带有注释的那行不能编译,解释如下:"两个方法都有相同的擦除,但都不覆盖另一个方法"。一方面,我理解它没有重写,因为第二个参数中的泛型类型是不同的。另一方面,在擦除之后,两个函数本质上具有相同的签名,因此也不会重载。但我正在努力理解为什么它不编译。如有任何帮助,不胜感激。

添加:即使我将签名更改为

public Object func(String str, List<Integer> lst) {return null;}

由于同样的原因,仍然不能编译。现在这些是完全不同的签名,所以这让我更困惑了。

From JLS 8.4.2:

两个方法或构造函数M和N如果具有相同的名称,相同的类型参数,则具有相同的签名(如果有的话)(§8.4.4),调整后的正式参数类型的类型参数N M,相同的形式参数类型.

这和你的代码有什么关系?

  1. 您发布的第一个方法签名是:

    public void func(String str, List<String> lst)
    

    这个签名只在编译时存在,因为它使用泛型。编译后,由于类型擦除,运行时签名将如下所示(List<String>变为List):

    public void func(String str, List lst)
    

  2. 你的例子中的第二个方法签名是:

    public void func(String str, List<Integer> lst)
    

    虽然起始点是不同的——一个整数列表而不是字符串列表——运行时签名也看到了类似的变化,将List<Integer>替换为List:

    public void func(String str, List lst)
    

即使代码指定不同的参数列表(List<String>vsList<Integer>)让你相信有两种不同的方法签名,两个签名实际上是相同的:

  • 它们都被命名为"func"和
  • 它们有相同的参数列表:String, list

在泛型擦除中,他们展示了一个类似于您所看到的Node<T>类型变为Node的示例。这也发生在你的例子中,List<String>变成了List

在类型擦除过程中,Java编译器擦除所有类型参数,如果类型参数有界,则将每个类型参数替换为其第一个绑定,如果类型参数没有界,则将每个类型参数替换为Object。

请注意,返回类型不是方法签名惟一性的一部分,这就是为什么将其更改为返回Object并没有什么区别。

下面是Java教程中关于类型擦除的更多信息,在几个地方添加了一点重点:

泛型被引入到Java语言中,以便在编译时提供更严格的类型检查并支持泛型编程。为了实现泛型,Java编译器将类型擦除应用于:

  • 将泛型类型中的所有类型参数替换为它们的边界,如果类型参数没有边界,则替换为Object。因此,生成的字节码只包含普通类、接口和方法
  • 插入类型强制转换以保证类型安全。
  • 生成桥接方法以保持扩展泛型类型中的多态性。类型擦除确保不为参数化类型创建新类;因此,泛型不会产生运行时开销。

相关内容

  • 没有找到相关文章

最新更新