generics类中的静态方法?

在Java中,我想有一些东西:

class Clazz<T> { static void doIt(T object) { // shake that booty } } 

但是我明白了

 无法对非静态typesT进行静态引用 

我不明白基本用法之外的generics,因此不能理解这一点。 这并没有帮助,我无法find关于这个问题在互联网上的很多信息。

有人可以通过类似的方式澄清这种使用是否可能吗? 另外,为什么我的原始尝试失败?

您不能在静态方法或静态字段中使用类的genericstypes参数。 类的types参数只在实例方法和实例字段的范围内。 对于静态字段和静态方法,它们在类的所有实例之间共享,即使是不同types参数的实例,显然它们不能依赖于特定的types参数。

这似乎并不像你的问题应该要求使用类的types参数。 如果你更详细地描述你正在做的事情,也许我们可以帮助你find一个更好的方法来做到这一点。

在实例化一个types之前,Java并不知道T是什么。

也许你可以通过调用Clazz<T>.doit(something)来执行静态方法,但是听起来你不能。

处理事物的另一种方法是将types参数放在方法本身中:

 static <U> void doIt(U object) 

这不会让你对U有正确的限制,但总比没有好。

我遇到了同样的问题。 我通过在java框架中下载Collections.sort的源代码find了我的答案。 我使用的答案是把这个癖好放在方法中,而不是在类的定义中。

所以这工作:

 public class QuickSortArray { public static <T extends Comparable> void quickSort(T[] array, int bottom, int top){ //do it } } 

当然,在阅读了上面的答案之后,我意识到如果不使用genomic类,这将是一个可接受的select:

 public static void quickSort(Comparable[] array, int bottom, int top){ //do it } 

在声明doIt()方法时(注意doIt()的方法签名中staticvoid之间join<T> doIt() ,可以通过使用generics方法的语法来完成你想要的操作:

 class Clazz<T> { static <T> void doIt(T object) { // shake that booty } } 

我得到了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); } } 

当我运行它时,将这些行打印到控制台:

动摇那个战利品'类com.eclipseoptions.datamanager.Clazz $ KC'!
摇那个战利品'类com.eclipseoptions.datamanager.Clazz $ SunshineBand'!

其他人已经回答了你的问题,但另外我可以彻底的推荐O'Reilly Java Generics的书。 这是一个微妙和复杂的主题,如果经常似乎没有任何限制,但本书做了很好的解释为什么javagenerics是他们的方式。

在错误中正确地提到了:不能对非静态typesT进行静态引用。原因是types参数T可以被任何types参数(例如Clazz<String>Clazz<integer>replace。静态字段/方法由类的所有非静态对象共享。

以下摘录摘自文档 :

类的静态字段是由类的所有非静态对象共享的类级variables。 因此,不允许使用types参数的静态字段。 考虑以下课程:

 public class MobileDevice<T> { private static T os; // ... } 

如果允许types参数的静态字段,那么下面的代码会被混淆:

 MobileDevice<Smartphone> phone = new MobileDevice<>(); MobileDevice<Pager> pager = new MobileDevice<>(); MobileDevice<TabletPC> pc = new MobileDevice<>(); 

因为静态字段os是由电话,寻呼机和pc共享的,所以os的实际types是什么? 它不能同时是智能手机,寻呼机和平板电脑。 因此,您不能创buildtypes参数的静态字段。

正如Chris在他的回答中指出的那样,你需要在方法中使用types参数,而不是在这种情况下使用类。 你可以这样写:

 static <E> void doIt(E object) 

像下面的东西会让你更接近

 class Clazz { public static <U extends Clazz> void doIt(U thing) { } } 

编辑:更详细的例子

 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()); } } 

我认为这个语法还没有被提及(在你想要一个没有参数的方法的情况下):

 class Clazz { static <T> T doIt() { // shake that booty } } 

和电话:

 String str = Clazz.<String>doIt(); 

希望这可以帮助别人。

当你为你的类指定一个genericstypes时,JVM知道它只有你的类的一个实例,而不是定义。 每个定义只有参数化types。

generics就像C ++中的模板一样工作,所以您应该先实例化您的类,然后使用具有指定types的函数。

也就是说,这是因为generics的“Erasure”属性。这意味着虽然我们定义了ArrayList<Integer>ArrayList<String> ,但是在编译时,它仍然是两种不同的具体types,但是在JVM运行时擦除通用types,只创build一个ArrayList类而不是两个类。 所以当我们为一个generics定义一个静态types方法或任何东西的时候,它就被这个generics的所有实例共享,在我的例子中它被ArrayList<Integer>ArrayList<String>共享。所以你得到这个错误。静态上下文中不允许类的genericstypes参数!

Rivenhill的BD:既然这个老问题去年得到了重新关注,让我们继续讨论一下吧。 doIt方法的主体根本就不做任何特定的事情。 这里是:

 public class Clazz<T> { static <T> void doIt(T object) { System.out.println("shake that booty '" + object.getClass().toString() + "' !!!"); } // ... } 

所以你可以完全删除所有types的variables,只是代码

 public class Clazz { static void doIt(Object object) { System.out.println("shake that booty '" + object.getClass().toString() + "' !!!"); } // ... } 

好。 但让我们回到最初的问题。 类声明中的第一个typesvariables是多余的。 只有第二个方法是必要的。 在这里,我们再次去,但它不是最终的答案,但:

 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"; } } 

然而,没什么大惊小怪的,因为下面的版本也是一样的。 所有它需要的是方法参数上的接口types。 任何地方都没有typesvariables。 这真的是原来的问题吗?

 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"; } }