gpt4 book ai didi

Java 使用泛型类型参数确定调用哪个方法?

转载 作者:IT老高 更新时间:2023-10-28 21:19:37 25 4
gpt4 key购买 nike

据我所知,Java 在运行时会丢弃泛型类型参数信息。它仅在编译时用于执行检查,例如,此特定方法调用是否有效。

今天我遇到了以下一段代码,其中,Java 似乎通过集合/列表类型参数来确定要调用哪个构造函数:

public static class MyClass {
public MyClass(final Collection<String> coll) {
System.out.println("Constructor 1");
}
public MyClass(final List<Integer> list) {
System.out.println("Constructor 2");
}
}

进行了以下调用:

new MyClass(new HashSet<String>()); // Constructor 1
new MyClass(new ArrayList<String>()); // Constructor 1
new MyClass(new ArrayList<Integer>()); // Constructor 2

现在,如果我删除类型参数:

public static class MyClass2 {
public MyClass2(final Collection coll) {
System.out.println("Constructor 1");
}
public MyClass2(final List list) {
System.out.println("Constructor 2");
}
}

...和我期望的一样的调用;使用列表参数的构造函数调用适用于“最精确”满足其需求的构造函数:

new MyClass2(new HashSet<String>()); // Constructor 1
new MyClass2(new ArrayList<String>()); // Constructor 2
new MyClass2(new ArrayList<Integer>()); // Constructor 2

似乎泛型信息被存储在编译的类(在本例中为 MyClass)中,毕竟并没有被丢弃,但应该被丢弃。我误会了什么?

最佳答案

这里发生的事情是编译器可以通过使用泛型来区分这两个构造函数,所以它创建字节码之前剥离泛型。

在中间情况下,它将告诉 VM 调用 MyClass2<init>(Collection) (即生成与此特定构造函数匹配的字节码)。

VM 不会尝试在运行时确定匹配的方法。那太慢了。相反,它依赖于编译器创建非常具体的指令。

这就是为什么即使通用信息在运行时已被删除,上面的代码仍然有效的原因。

[编辑]澄清:字节码包含编译器可以看到和使用的附加信息。您可以通过反射获得相同的信息。

删除意味着字节码解释器和 JIT 不关心泛型,这就是为什么你不能拥有 setFoo(List<String>)setFoo(List<Integer>)在同一个类中:虽然编译器可以区分两者,但运行时不能。

具体来说,当您通过反射检查方法时,您将获得泛型信息,但字节码解释器/JIT 不使用反射。相反,它使用压缩的方法签名,其内容类似于 Method com/pany/Type/setFoo(Ljava.util.List;)V - 这里不再有泛型了。

相关:

关于Java 使用泛型类型参数确定调用哪个方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18446737/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com