你能解释为什么以下有效吗?
public class GenericsTest<T> {
public void doSomething(T v1, T v2) {
}
public static <T> void doSomethingStatic(T v1, T v2) {
}
public static <T> void doSomethingStaticList(List<T> v1, List<T> v2)
{
}
public static void main(String[] args) {
GenericsTest<String> gt = new GenericsTest<>();
// OK
gt.doSomething("abc", "abc");
// Not OK
gt.doSomething(1, "abc");
// OK
doSomethingStatic(1, 2);
// Still OK
doSomethingStatic(1, "abc");
// So why is this not OK?
List<String> list1=new LinkedList<>();
List<Integer> list2=new LinkedList<>();
doSomethingStaticList(list1,list2);
}
}
T v1, T v2
应该是doSomethingStatic
中的相同类型,但我仍然可以传递不同的类型(整数和字符串)。
如果doSomethingStatic()
默认采用普通超类,为什么doSomethingStaticList()
不能使用不同的类型?
答案 0 :(得分:23)
在非静态情况下,您在创建T
的实例时将String
定义为GenericsTest
。因此传递int
将导致编译错误。如果你做gt.doSomething(1, 2)
它也会失败。
在静态情况下,您不手动定义T
,它是从参数派生的。它将是这两个类的第一个常见超类 - 在本例中为Object
。您可能希望使用有界通配符,例如<T extends Number>
或<T extends CharSequence>
。
请注意,您在这里有两个不同的T
:
GenericsTest<T>
public static <T> void doSomethingStatic(T v1, T v2)
泛型参数的声明是在您编写<T>
时。在这种情况下,您可以使用不同的字母以避免混淆。
答案 1 :(得分:14)
这是有效的,因为静态方法中的T
是自己的类型参数,而不是实例的T
参数。 strong>成员方法。重命名以澄清:
public static class GenericsTest<T> {
public void doSomething(T v1, T v2) {
}
public static <V> void doSomethingStatic(V v1, V v2) {
}
//...
因此,如果doSomething(...)
您的实例类型参数值为String
,那么这是一个错误。如果类型参数的静态doSomethingStatic(...)
值不同:
GenericsTest.doSomethingStatic(1, "abc"); //ok
GenericsTest.<Object>doSomethingStatic(1, "abc"); //ok
GenericsTest.<String>doSomethingStatic(1, "abc"); //not ok
new GenericsTest<String>().doSomething(1, "abc"); //not ok
答案 2 :(得分:2)
首先是一点理论:
发生了什么:
您可以在没有静态方法的情况下尝试此示例:
public class GenericsTest<T> {
public void doSomething(T v1, T v2) {
}
public <T> void doSomething2(T v1, T v2) {
}
public static void main(String[] args) {
GenericsTest<String> gt = new GenericsTest<>();
// ok
gt.doSomething("abc", "abc");
// Not ok
gt.doSomething(1, "abc");
// ok
gt.doSomething2(1, 2);
// Still ok
gt.doSomething2(1, "abc");
}
}
答案 3 :(得分:0)
在静态情况下,您不手动定义T,它是从参数派生的。 在doSomethingStaticList(list1,list2)的情况下,其中list1是String泛型List而list2是Integer泛型List。编译器推断算法将无法识别,因为列表和列表不属于任何常见类型。