Java 泛型类中的静态方法?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/936377/
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 method in a generic class?
提问by André Chalella
In Java, I'd like to have something as:
在 Java 中,我想要一些东西:
class Clazz<T> {
static void doIt(T object) {
// ...
}
}
But I get
但我得到
Cannot make a static reference to the non-static type T
I don't understand generics beyond the basic uses and thus can't make much sense of that. It doesn't help that I wasn't able to find much info on the internet about the subject.
我不了解基本用途之外的泛型,因此无法理解这一点。我无法在互联网上找到有关该主题的太多信息,这无济于事。
Could someone clarify if such use is possible, by a similar manner? Also, why was my original attempt unsuccessful?
有人可以通过类似的方式澄清这种使用是否可能吗?另外,为什么我最初的尝试不成功?
采纳答案by newacct
You can't use a class's generic type parameters in static methods or static fields. The class's type parameters are only in scope for instance methods and instance fields. For static fields and static methods, they are shared among all instances of the class, even instances of different type parameters, so obviously they cannot depend on a particular type parameter.
您不能在静态方法或静态字段中使用类的泛型类型参数。类的类型参数仅在实例方法和实例字段的范围内。对于静态字段和静态方法,它们在类的所有实例之间共享,甚至是不同类型参数的实例,因此显然它们不能依赖于特定的类型参数。
It doesn't seem like your problem should require using the class's type parameter. If you describe what you are trying to do in more detail, maybe we can help you find a better way to do it.
您的问题似乎不需要使用类的类型参数。如果您更详细地描述您正在尝试做的事情,也许我们可以帮助您找到更好的方法。
回答by Jason S
Java doesn't know what T
is until you instantiate a type.
T
在实例化类型之前,Java 不知道是什么。
Maybe you can execute static methods by calling Clazz<T>.doit(something)
but it sounds like you can't.
也许你可以通过调用来执行静态方法,Clazz<T>.doit(something)
但听起来你不能。
The other way to handle things is to put the type parameter in the method itself:
另一种处理方式是将类型参数放在方法本身中:
static <U> void doIt(U object)
which doesn't get you the right restriction on U, but it's better than nothing....
这不会让你对 U 进行正确的限制,但总比没有好......
回答by Marcin Cylke
When you specify a generic type for your class, JVM know about it only having an instance of your class, not definition. Each definition has only parametrized type.
当你为你的类指定一个泛型类型时,JVM 知道它只有你的类的一个实例,而不是定义。每个定义只有参数化类型。
Generics work like templates in C++, so you should first instantiate your class, then use the function with the type being specified.
泛型的工作方式类似于 C++ 中的模板,因此您应该首先实例化您的类,然后使用指定类型的函数。
回答by Chris
I ran into this same problem. I found my answer by downloading the source code for Collections.sort
in the java framework. The answer I used was to put the <T>
generic in the method, not in the class definition.
我遇到了同样的问题。我通过下载Collections.sort
java 框架中的源代码找到了我的答案。我使用的答案是将<T>
泛型放在方法中,而不是放在类定义中。
So this worked:
所以这有效:
public class QuickSortArray {
public static <T extends Comparable> void quickSort(T[] array, int bottom, int top){
//do it
}
}
Of course, after reading the answers above I realized that this would be an acceptable alternative without using a generic class:
当然,在阅读了上面的答案后,我意识到这将是一个可以接受的替代方案,而无需使用泛型类:
public static void quickSort(Comparable[] array, int bottom, int top){
//do it
}
回答by ekj
Something like the following would get you closer
像下面这样的东西会让你更接近
class Clazz
{
public static <U extends Clazz> void doIt(U thing)
{
}
}
EDIT: Updated example with more detail
编辑:更详细的更新示例
public abstract class Thingo
{
public static <U extends Thingo> void doIt(U p_thingo)
{
p_thingo.thing();
}
protected abstract void thing();
}
class SubThingoOne extends Thingo
{
@Override
protected void thing()
{
System.out.println("SubThingoOne");
}
}
class SubThingoTwo extends Thingo
{
@Override
protected void thing()
{
System.out.println("SuThingoTwo");
}
}
public class ThingoTest
{
@Test
public void test()
{
Thingo t1 = new SubThingoOne();
Thingo t2 = new SubThingoTwo();
Thingo.doIt(t1);
Thingo.doIt(t2);
// compile error --> Thingo.doIt(new Object());
}
}
回答by BD at Rivenhill
It is possible to do what you want by using the syntax for generic methods when declaring your doIt()
method (notice the addition of <T>
between static
and void
in the method signature of doIt()
):
在声明您的方法时,可以通过使用泛型方法的语法来做您想做的事情doIt()
(注意在 的方法签名中和<T>
之间的添加):static
void
doIt()
class Clazz<T> {
static <T> void doIt(T object) {
// shake that booty
}
}
I got Eclipse editor to accept the above code without the Cannot make a static reference to the non-static type T
error and then expanded it to the following working program (complete with somewhat age-appropriate cultural reference):
我让 Eclipse 编辑器在没有Cannot make a static reference to the non-static type T
错误的情况下接受上面的代码,然后将其扩展为以下工作程序(完成了一些适合年龄的文化参考):
public class Clazz<T> {
static <T> void doIt(T object) {
System.out.println("shake that booty '" + object.getClass().toString()
+ "' !!!");
}
private static class KC {
}
private static class SunshineBand {
}
public static void main(String args[]) {
KC kc = new KC();
SunshineBand sunshineBand = new SunshineBand();
Clazz.doIt(kc);
Clazz.doIt(sunshineBand);
}
}
Which prints these lines to the console when I run it:
当我运行它时,它将这些行打印到控制台:
shake that booty 'class com.eclipseoptions.datamanager.Clazz$KC' !!!
shake that booty 'class com.eclipseoptions.datamanager.Clazz$SunshineBand' !!!
动摇那个战利品'class com.eclipseoptions.datamanager.Clazz$KC'!!!
动摇那个战利品'class com.eclipseoptions.datamanager.Clazz$SunshineBand'!!!
回答by akhil_mittal
It is correctly mentioned in the error: you cannot make a static reference to non-static type T. The reason is the type parameter T
can be replaced by any of the type argument e.g. Clazz<String>
or Clazz<integer>
etc. But static fields/methods are shared by all non-static objects of the class.
在错误中正确提到:您不能对非静态类型 T 进行静态引用。原因是类型参数T
可以被任何类型参数替换,例如Clazz<String>
或Clazz<integer>
等。但是所有非静态字段/方法都共享静态字段/方法-类的静态对象。
The following excerpt is taken from the doc:
以下摘录自文档:
A class's static field is a class-level variable shared by all non-static objects of the class. Hence, static fields of type parameters are not allowed. Consider the following class:
public class MobileDevice<T> { private static T os; // ... }
If static fields of type parameters were allowed, then the following code would be confused:
MobileDevice<Smartphone> phone = new MobileDevice<>(); MobileDevice<Pager> pager = new MobileDevice<>(); MobileDevice<TabletPC> pc = new MobileDevice<>();
Because the static field os is shared by phone, pager, and pc, what is the actual type of os? It cannot be Smartphone, Pager, and TabletPC at the same time. You cannot, therefore, create static fields of type parameters.
类的静态字段是类的所有非静态对象共享的类级变量。因此,不允许使用类型参数的静态字段。考虑以下类:
public class MobileDevice<T> { private static T os; // ... }
如果允许类型参数的静态字段,那么下面的代码会被混淆:
MobileDevice<Smartphone> phone = new MobileDevice<>(); MobileDevice<Pager> pager = new MobileDevice<>(); MobileDevice<TabletPC> pc = new MobileDevice<>();
因为静态字段os是phone、pager、pc共享的,那么os的实际类型是什么?不能同时是智能手机、寻呼机和平板电脑。因此,您不能创建类型参数的静态字段。
As rightly pointed out by chris in his answeryou need to use type parameter with the method and not with the class in this case. You can write it like:
正如克里斯在他的回答中正确指出的那样,在这种情况下,您需要将类型参数与方法一起使用,而不是与类一起使用。你可以这样写:
static <E> void doIt(E object)
回答by Oreste Viron
I think this syntax has not been mentionned yet (in the case you want a method without arguments) :
我认为这个语法还没有被提及(如果你想要一个没有参数的方法):
class Clazz {
static <T> T doIt() {
// shake that booty
}
}
And the call :
和电话:
String str = Clazz.<String>doIt();
Hope this help someone.
希望这有助于某人。
回答by Oreste Viron
Also to put it in simple terms, it happens because of the "Erasure" property of the generics.Which means that although we define ArrayList<Integer>
and ArrayList<String>
, at the compile time it stays as two different concrete types but at the runtime the JVM erases generic types and creates only one ArrayList class instead of two classes. So when we define a static type method or anything for a generic, it is shared by all instances of that generic, in my example it is shared by both ArrayList<Integer>
and ArrayList<String>
.That's why you get the error.A Generic Type Parameter of a Class Is Not Allowed in a Static Context!
简而言之,它的发生是因为泛型的“擦除”属性。这意味着虽然我们定义了ArrayList<Integer>
和ArrayList<String>
,但在编译时它仍然是两种不同的具体类型,但在运行时 JVM 擦除了泛型类型和只创建一个 ArrayList 类而不是两个类。因此,当我们为泛型定义静态类型方法或任何东西时,它由该泛型的所有实例共享,在我的示例中,它由ArrayList<Integer>
和共享。这ArrayList<String>
就是您收到错误的原因。类的泛型类型参数不是在静态上下文中允许!
回答by Hubert Kauker
@BD at Rivenhill: Since this old question has gotten renewed attention last year, let us go on a bit, just for the sake of discussion.
The body of your doIt
method does not do anything T
-specific at all. Here it is:
@Rivenhill 的 BD:由于这个老问题在去年再次受到关注,让我们继续讨论一下,只是为了讨论。您的doIt
方法的主体根本不做任何T
特定的事情。这里是:
public class Clazz<T> {
static <T> void doIt(T object) {
System.out.println("shake that booty '" + object.getClass().toString()
+ "' !!!");
}
// ...
}
So you can entirely drop all type variables and just code
所以你可以完全删除所有类型变量而只写代码
public class Clazz {
static void doIt(Object object) {
System.out.println("shake that booty '" + object.getClass().toString()
+ "' !!!");
}
// ...
}
Ok. But let's get back closer to the original problem. The first type variable on the class declaration is redundant. Only the second one on the method is needed. Here we go again, but it is not the final answer, yet:
好的。但是让我们回到更接近原始问题的地方。类声明中的第一个类型变量是多余的。只需要方法上的第二个。我们又来了,但这还不是最终答案:
public class Clazz {
static <T extends Saying> void doIt(T object) {
System.out.println("shake that booty "+ object.say());
}
public static void main(String args[]) {
Clazz.doIt(new KC());
Clazz.doIt(new SunshineBand());
}
}
// Output:
// KC
// Sunshine
interface Saying {
public String say();
}
class KC implements Saying {
public String say() {
return "KC";
}
}
class SunshineBand implements Saying {
public String say() {
return "Sunshine";
}
}
However, it's all too much fuss about nothing, since the following version works just the same way. All it needs is the interface type on the method parameter. No type variables in sight anywhere. Was that really the original problem?
然而,这一切都太过分了,因为以下版本的工作方式相同。它所需要的只是方法参数上的接口类型。任何地方都看不到类型变量。这真的是最初的问题吗?
public class Clazz {
static void doIt(Saying object) {
System.out.println("shake that booty "+ object.say());
}
public static void main(String args[]) {
Clazz.doIt(new KC());
Clazz.doIt(new SunshineBand());
}
}
interface Saying {
public String say();
}
class KC implements Saying {
public String say() {
return "KC";
}
}
class SunshineBand implements Saying {
public String say() {
return "Sunshine";
}
}