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()
的方法签名中static
和void
之间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"; } }