下面我有两个通用方法。两者都有两个参数化类型 T 和 V 扩展 T。第一个方法 foo 接受类型 T 和 V 的参数。奇怪的是,我可以调用 foo("hello", new Integer(10)) 并且它会编译并运行,即使 Integer显然不扩展 String.第二种方法 bar 采用 List< T > 和 List< V > 类型的参数。在这里,我无法调用 bar,向其传递字符串列表和整数列表。为什么后者限制类型,而前者不限制。
public class GenMeth {
public static void main(String[] args) {
List<String> s_list = new ArrayList<>();
s_list.add("hello");
List<Integer> i_list = new ArrayList<>();
i_list.add(10);
foo("hello", new Integer(10)); // will compile - why?
bar(s_list, i_list); // won't compile - understandable
}
public static <T,V extends T> void foo(T obj1, V obj2) {
// do something
}
public static <T,V extends T> void bar(List<T> list1, List<V> list2) {
// do something
}
}
最佳答案
foo
总是能够接受任何引用类型的两个参数,因为 T
和V
可以选择为Object
,任何引用类型都是 Object
的子类型。所以foo
不妨声明为 public static void foo(Object obj1, Object obj2)
;这没什么区别。从它的声明方式来看,没有什么 foo
可以用它的任何一个参数来做,除了 Object
可以做的事情,由于类型变量没有界限,因此除了它们都是 Object
之外没有任何限制.
bar
不同是因为类型变量位于类型参数中。泛型是不变的 -- List<String>
不是 List<Object>
的子类型(反之亦然)即使 String
是 Object
的子类型。因此,第一个参数的类型为 List<T>
,它迫使T
与传递的参数的类型参数完全匹配;即通过传递 List<String>
作为第一个参数,它强制 T
成为String
;不可能Object
或者其他什么——它不会兼容。并且由于第二个参数的类型是 List<V>
和V
延伸T
,这意味着第二个参数的类型参数必须是 String
或 String
的子类型。 (p.s. bar
也可以简单一点地声明为 public static <T> void bar(List<T> list1, List<? extends T> list2)
)
关于java - 在Java中,为什么我只能使用泛型来限制集合参数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47087814/