Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/video/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 方法与类型中的另一个方法具有相同的擦除_Java_Generics - Fatal编程技术网

Java 方法与类型中的另一个方法具有相同的擦除

Java 方法与类型中的另一个方法具有相同的擦除,java,generics,Java,Generics,为什么在同一个类中使用以下两种方法是不合法的 class Test{ void add(Set<Integer> ii){} void add(Set<String> ss){} } 方法,但情况并非总是如此 如果您想让两个构造函数接受这些参数,这就特别麻烦了,因为这样您就不能只更改其中一个构造函数的名称

为什么在同一个类中使用以下两种方法是不合法的

class Test{
   void add(Set<Integer> ii){}
   void add(Set<String> ss){}
}
方法,但情况并非总是如此


如果您想让两个
构造函数
接受这些参数,这就特别麻烦了,因为这样您就不能只更改其中一个
构造函数的名称

)被删除,因此您将得到两个具有相同签名的方法(您在错误中看到的
添加(设置)
)。这是不允许的,因为运行时不知道对每种情况使用哪个


如果Java曾经得到具体化的泛型,那么您可以这样做,但现在可能不太可能了。

编译器可能会将Java字节码中的Set(Integer)转换为Set(Object)。如果是这种情况,Set(Integer)将仅在编译阶段用于语法检查。

这是因为Java泛型是用实现的

在编译时,您的方法将被转换为如下内容:

方法解析发生在编译时,不考虑类型参数。()


这两种方法都具有相同的签名,但没有类型参数,因此存在错误。

问题是
Set
Set
实际上被视为JVM中的
Set
。为集合选择一个类型(在您的例子中是字符串或整数)只是编译器使用的语法糖。JVM无法区分
Set
Set

此规则旨在避免仍然使用原始类型的遗留代码中的冲突

下面举例说明了为什么不允许这样做,假设在将泛型引入Java之前,我编写了如下代码:

class CollectionConverter {
  List toList(Collection c) {...}
}
class Overrider extends CollectionConverter{
  List toList(Collection c) {...}
}
class Overrider extends CollectionConverter {
  @Override
  List toList(Collection c) {...}
  @Override
  <T> List<T> toList(Collection<T> c) {...}
}
你扩展了我的课堂,就像这样:

class CollectionConverter {
  List toList(Collection c) {...}
}
class Overrider extends CollectionConverter{
  List toList(Collection c) {...}
}
class Overrider extends CollectionConverter {
  @Override
  List toList(Collection c) {...}
  @Override
  <T> List<T> toList(Collection<T> c) {...}
}
在引入泛型之后,我决定更新我的库

class CollectionConverter {
  <T> List<T> toList(Collection<T> c) {...}
}
由于原始类型的重写等价性,这两种方法都以有效的形式重写
toList(Collection)
方法。但当然,编译器需要解析单个方法。为了消除这种歧义,类不允许有多个重写等效的方法,即在擦除后具有相同参数类型的多个方法


关键在于,这是一种语言规则,旨在维护与使用原始类型的旧代码的兼容性。它不是类型参数擦除所需的限制;因为方法解析发生在编译时,向方法标识符添加泛型类型就足够了。

定义一个没有类型的方法,比如
void add(Set ii){}


您可以根据自己的选择在调用方法时提及类型。它适用于任何类型的集合。

我在尝试编写以下内容时遇到了这种情况:
Continuable callAsync(可调用代码){….}
Continuable callAsync(Callable veryAsyncCode){…}
它们成为编译器的两个定义
Continuable callAsync(Callable veryAsyncCode){…}

类型擦除字面上是指从泛型中擦除类型参数信息。 这很烦人,但这是Java暂时存在的一个限制。 对于构造函数来说,没有什么可以做的,例如,在构造函数中有两个新的子类专门使用不同的参数。 或者改用初始化方法。。。(虚拟构造函数?)具有不同的名称

对于类似的操作方法,重命名会有所帮助,如

类测试{
无效加法器(集合ii){}
void addStrings(Set ss){}
}

或者使用一些更具描述性的名称,对oyu案例进行自我记录,如
addNames
addIndexes
或诸如此类。

从技术上讲,它只是原始类型
。泛型不存在于字节码中,它们是用于强制转换的语法糖,并提供编译时类型安全性。很抱歉,您的答案(以及其他答案)没有解释为什么这里有错误。重载解析是在编译时完成的,编译器肯定拥有所需的类型信息,可以根据地址或字节码中引用的任何方法来决定链接哪个方法,我认为字节码不是签名。我甚至认为有些编译器会允许这种方法进行编译。@Stillgar如何阻止通过反射调用或检查该方法?Class.getMethods()返回的方法列表将有两个相同的方法,这是没有意义的。反射信息可以/应该包含处理泛型所需的元数据。如果没有,那么当您导入已经编译的库时,Java编译器如何知道泛型方法呢?那么getMethod方法需要修复。例如,引入一个重载,它指定泛型重载,并使原始方法仅返回非泛型版本,而不返回任何声明为泛型的方法。当然,这应该在1.5版中完成。如果他们现在这样做,就会破坏方法的向后兼容性。我坚持我的说法,即类型擦除并不决定这种行为。可能是由于资源有限,实现没有得到足够的工作。这不是一个精确的答案,但它确实很快在一个有用的虚构故事中总结了这个问题:方法签名太相似,编译器可能无法分辨差异,然后您将得到“未解决的编译问题”的确,JVM运行时没有信息来区分每个
,但是由于方法解析发生在编译时,当必要的信息可用时,这是不相关的。问题是允许这些重载会与允许原始类型冲突,因此它们在Java语法中是非法的。@erickson即使编译器知道要调用什么方法,也不能像在字节码中一样,它们看起来完全相同。您需要更改方法调用的指定方式,如
(Ljava/util/Co