java 静态泛型方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/39849482/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Static generic methods
提问by Tony
Can you explain why the following works?
你能解释为什么下面的工作?
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
should be the same type in doSomethingStatic
, but I'm still able to pass different types(integer and string).
T v1, T v2
应该是相同的类型doSomethingStatic
,但我仍然可以传递不同的类型(整数和字符串)。
If doSomethingStatic()
takes a common super class by default, why doesn't doSomethingStaticList()
work with different types?
如果doSomethingStatic()
默认采用一个通用的超类,为什么不能doSomethingStaticList()
使用不同的类型?
采纳答案by Jaroslaw Pawlak
In non-static case you define T
as String
when you create instance of GenericsTest
. Hence passing an int
will give compile error. If you did gt.doSomething(1, 2)
it would fail as well.
在非静态情况下,您定义T
为String
创建GenericsTest
. 因此传递 anint
会导致编译错误。如果你这样做,gt.doSomething(1, 2)
它也会失败。
In static case, you don't define T
manually, it is derived from parameters. It will be the first common superclass of both classes - which in this case is Object
. You might want to use bounded wildcard, e.g. <T extends Number>
or <T extends CharSequence>
.
在静态情况下,您不T
手动定义,它是从参数派生的。它将是两个类的第一个公共超类 - 在这种情况下是Object
. 您可能想要使用有界通配符,例如<T extends Number>
或<T extends CharSequence>
。
Note that you have two different T
s here:
请注意,这里有两个不同的T
s:
GenericsTest<T>
public static <T> void doSomethingStatic(T v1, T v2)
GenericsTest<T>
public static <T> void doSomethingStatic(T v1, T v2)
The declaration of generic parameter is whenever you write <T>
. You can use different letters in this case to avoid confusion.
泛型参数的声明是每当您编写<T>
. 在这种情况下,您可以使用不同的字母以避免混淆。
回答by Philip Voronov
This works because T
in your static method is his owntype parameter, not the T
parameter for instancethat used in your member method. Rename it to clarify:
这是有效的,因为T
在您的静态方法中是他自己的类型参数,而不是例如在您的成员方法中使用的T
参数。重命名以澄清:
public static class GenericsTest<T> {
public void doSomething(T v1, T v2) {
}
public static <V> void doSomethingStatic(V v1, V v2) {
}
//...
So in case of doSomething(...)
your instance type parameter value is String
so it's an error. In case of static doSomethingStatic(...)
value of type parameter is different:
因此,如果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
回答by Aris2World
First a bit of theory:
先说点理论:
- Generic methods are methods that introduce their own type parameters Java Tutorials - Generic Methods
- Type inference is a Java compiler's ability to look at each method invocation and corresponding declaration to determine the type argument (or arguments) that make the invocation applicable Java Tutorials - Type inference
- 泛型方法是引入自己的类型参数的方法 Java 教程 - 泛型方法
- 类型推断是 Java 编译器查看每个方法调用和相应声明以确定使调用适用的类型参数(或参数)的能力Java 教程 - 类型推断
So what happen:
那么会发生什么:
- when a generic expression precede the return value then a new generic type variable is "declared". So the T of the class declaration is different (for the compiler) from the T of the method declaration.
- the compiler apply type inference and in your example it determine that the suitable type to apply method invocation is Object
- 当泛型表达式位于返回值之前时,就会“声明”一个新的泛型类型变量。所以类声明的 T 与方法声明的 T 不同(对于编译器)。
- 编译器应用类型推断,在您的示例中,它确定应用方法调用的合适类型是 Object
You can try also this example without static method:
您也可以在没有静态方法的情况下尝试此示例:
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");
}
}
回答by Aman Goyal
In static case, you don't define T manually, it is derived from parameters. In the case doSomethingStaticList(list1,list2) where list1 is String generic List while list2 is Integer generic List. Compiler inference algorithm won't be able to recognize because List and List doesn't belong to any common type.
在静态情况下,您不手动定义 T,它是从参数派生的。在 doSomethingStaticList(list1,list2) 的情况下,其中 list1 是字符串通用列表,而 list2 是整数通用列表。编译器推理算法将无法识别,因为 List 和 List 不属于任何常见类型。