在Java中,我希望具有以下内容:
class Clazz<T> {
static void doIt(T object) {
// ...
}
}
但是我明白了
无法静态引用非静态类型T
我不了解泛型的基本用途,因此没有太多意义。我无法在互联网上找到有关该主题的很多信息,这无济于事。
有人可以通过类似的方式澄清这种使用是否可能吗?另外,为什么我最初的尝试失败了?
在Java中,我希望具有以下内容:
class Clazz<T> {
static void doIt(T object) {
// ...
}
}
但是我明白了
无法静态引用非静态类型T
我不了解泛型的基本用途,因此没有太多意义。我无法在互联网上找到有关该主题的很多信息,这无济于事。
有人可以通过类似的方式澄清这种使用是否可能吗?另外,为什么我最初的尝试失败了?
Answers:
您不能在静态方法或静态字段中使用类的泛型类型参数。该类的类型参数仅在实例方法和实例字段的范围内。对于静态字段和静态方法,它们在类的所有实例之间共享,即使是不同类型参数的实例也是如此,因此,显然,它们不能依赖于特定的类型参数。
看来您的问题似乎不需要使用类的type参数。如果您更详细地描述您要尝试做的事情,也许我们可以帮助您找到一种更好的方法。
T
直到实例化类型,Java才知道是什么。
也许您可以通过调用来执行静态方法,Clazz<T>.doit(something)
但这听起来似乎不行。
处理事物的另一种方法是将类型参数放在方法本身中:
static <U> void doIt(U object)
并没有对U施加正确的限制,但是总比没有好....
我遇到了同样的问题。我通过下载Collections.sort
Java框架中的源代码找到了答案。我使用的答案是将<T>
泛型放入方法中,而不放在类定义中。
所以这工作:
public class QuickSortArray {
public static <T extends Comparable> void quickSort(T[] array, int bottom, int top){
//do it
}
}
当然,在阅读了以上答案之后,我意识到如果不使用泛型类,这将是可以接受的替代方案:
public static void quickSort(Comparable[] array, int bottom, int top){
//do it
}
T extends XXX
语法的示例的道具。
Comparable
。试试吧<T extends Comparable<? super T>>
。
在声明您的方法时,可以通过使用通用方法的语法来做您想做的事情doIt()
(请注意,<T>
在static
和之间添加void
了方法签名doIt()
):
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”!
<T>
屏蔽第一个class C { int x; C(int x) { ... } }
参数的方式与参数x
屏蔽字段的方式相同x
。
static <E extends SomeClass> E foo(E input){return input;}
为每一个方法的时候,我想这样做static <E extends SomeClass>; //static generic type defined only once and reused
static E foo(E input){return input;}
static E bar(E input){return input;}
//...etc...
我认为还没有提到此语法(如果您想要一个没有参数的方法):
class Clazz {
static <T> T doIt() {
// shake that booty
}
}
并致电:
String str = Clazz.<String>doIt();
希望这对某人有帮助。
<String>
因为它只是推断类型参数,因为您将其分配给变量。如果您不分配它,它只是推断Object
。
错误中已正确提及:您不能对非静态类型T进行静态引用。原因是T
可以用任何类型参数(例如Clazz<String>
或)替换类型参数。Clazz<integer>
等等)。但是静态字段/方法由所有非静态共享类的-static对象。
以下摘录摘自doc:
类的静态字段是由该类的所有非静态对象共享的类级别变量。因此,不允许使用类型参数的静态字段。考虑以下类别:
public class MobileDevice<T> { private static T os; // ... }
如果允许使用类型参数的静态字段,则以下代码将被混淆:
MobileDevice<Smartphone> phone = new MobileDevice<>(); MobileDevice<Pager> pager = new MobileDevice<>(); MobileDevice<TabletPC> pc = new MobileDevice<>();
因为静态字段os由电话,寻呼机和pc共享,所以os的实际类型是什么?它不能同时是Smartphone,Pager和TabletPC。因此,您不能创建类型参数的静态字段。
正如chris在他的答案中正确指出的那样,在这种情况下,您需要在方法中使用类型参数,而不是对类使用。您可以这样写:
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());
}
}
当为类指定泛型类型时,JVM会知道它只有类的实例,而没有定义。每个定义只有参数化类型。
泛型的工作方式类似于C ++中的模板,因此您应该首先实例化您的类,然后使用具有指定类型的函数。
Clazz<int>::doIt( 5 )
)
简而言之,它的发生是由于泛型的“ Erasure”属性所引起的。这意味着,尽管我们定义了ArrayList<Integer>
和ArrayList<String>
,但在编译时它仍然是两种不同的具体类型,但在运行时,JVM会擦除泛型类型,并且仅创建一个ArrayList类,而不是两个类。因此,当我们定义一个静态类型的方法或任何一个通用的,它是由通用的所有实例共享,在我的例子,同时由共享ArrayList<Integer>
和ArrayList<String>
。那就是为什么你得到一个类不是的error.A泛型类型参数在静态上下文中允许!
@BD in Rivenhill:由于这个老问题在去年得到了重新的关注,让我们继续讨论一下,只是为了讨论。doIt
方法的主体根本不执行任何T
特定操作。这里是:
public class Clazz<T> {
static <T> void doIt(T object) {
System.out.println("shake that booty '" + object.getClass().toString()
+ "' !!!");
}
// ...
}
因此,您可以完全删除所有类型变量,而只需编写代码
public class Clazz {
static void doIt(Object object) {
System.out.println("shake that booty '" + object.getClass().toString()
+ "' !!!");
}
// ...
}
好。但是,让我们更接近原始问题。类声明上的第一个类型变量是多余的。仅需要该方法的第二个。这里我们再次进行,但这还不是最终答案:
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";
}
}
但是,所有内容都大惊小怪,因为以下版本的工作方式相同。它所需要的只是方法参数上的接口类型。在任何地方都看不到类型变量。那真的是最初的问题吗?
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";
}
}