Java 泛型方法。为什么T被推导为Map?
Java generic method. Why is T deduced to be Map?
考虑以下代码
class MyClass {
public MyClass(Map<String, String> m) {
System.out.println("map");
}
public MyClass(SortedMap<String, String> m) {
System.out.println("sortedmap");
}
}
public class Test {
public <T extends Map<String,String>> Test(T t) {
new MyClass(t);
}
public static void main(String[] args) {
new Test(new TreeMap<String,String>());
}
}
它打印 map
。为什么 T
被推断为 Map
而不是 public <T extends Map<String, String>> Test(T t)
中的 SortedMap
?有没有办法改变这种行为,以便为 MyClass
使用最具体的构造函数?
解析调用MyClass
的构造函数是在编译时完成的。当编译器编译Test
构造函数的代码时,它不知道T
到底是什么,它只知道它保证是Map<String, String>
,所以它不能做任何其他事情而不是将构造函数调用绑定到采用 Map
的构造函数。
在您的代码中 T
是 TreeMap
的知识仅存在于方法 main
的主体内,而不存在于外部。例如,考虑如果您添加 Test
构造函数的第二个调用者实际传递 HashMap
.
会发生什么
Java 泛型的工作原理是,泛型方法的代码只为所有可能的泛型参数值编译一次(并且只在字节码中出现一次),不像其他语言那样有一个副本每个泛型类型的泛型方法。
一般来说,在 Java 中不可能让代码中的单个 method/constructor 调用实际调用 不同的 methods/constructors运行时取决于参数的类型。这仅适用于取决于被调用对象的运行时类型的方法调用(使用覆盖方法的动态绑定)。
通过查看参数的静态类型,重载(您在此处拥有的)仅在编译时起作用。
这种情况的典型解决方案是在 MyClass
的构造函数中使用 instanceof SortedMap
检查。
另一个可能的(更优雅的)解决方案是访问者模式,但这只适用于为它准备的 classes(所以如果你不将它们包装在 [=39= 中,则不适用于 Map
个实例] 自己的)。
考虑以下代码
class MyClass {
public MyClass(Map<String, String> m) {
System.out.println("map");
}
public MyClass(SortedMap<String, String> m) {
System.out.println("sortedmap");
}
}
public class Test {
public <T extends Map<String,String>> Test(T t) {
new MyClass(t);
}
public static void main(String[] args) {
new Test(new TreeMap<String,String>());
}
}
它打印 map
。为什么 T
被推断为 Map
而不是 public <T extends Map<String, String>> Test(T t)
中的 SortedMap
?有没有办法改变这种行为,以便为 MyClass
使用最具体的构造函数?
解析调用MyClass
的构造函数是在编译时完成的。当编译器编译Test
构造函数的代码时,它不知道T
到底是什么,它只知道它保证是Map<String, String>
,所以它不能做任何其他事情而不是将构造函数调用绑定到采用 Map
的构造函数。
在您的代码中 T
是 TreeMap
的知识仅存在于方法 main
的主体内,而不存在于外部。例如,考虑如果您添加 Test
构造函数的第二个调用者实际传递 HashMap
.
Java 泛型的工作原理是,泛型方法的代码只为所有可能的泛型参数值编译一次(并且只在字节码中出现一次),不像其他语言那样有一个副本每个泛型类型的泛型方法。
一般来说,在 Java 中不可能让代码中的单个 method/constructor 调用实际调用 不同的 methods/constructors运行时取决于参数的类型。这仅适用于取决于被调用对象的运行时类型的方法调用(使用覆盖方法的动态绑定)。
通过查看参数的静态类型,重载(您在此处拥有的)仅在编译时起作用。
这种情况的典型解决方案是在 MyClass
的构造函数中使用 instanceof SortedMap
检查。
另一个可能的(更优雅的)解决方案是访问者模式,但这只适用于为它准备的 classes(所以如果你不将它们包装在 [=39= 中,则不适用于 Map
个实例] 自己的)。