210

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

class Clazz<T> {
  static void doIt(T object) {
    // ...
  }
}

但我明白了

无法对非静态类型 T 进行静态引用

除了基本用途之外,我不了解泛型,因此对此没有多大意义。我无法在互联网上找到有关该主题的大量信息,这无济于事。

有人可以通过类似的方式澄清这种使用是否可能吗?另外,为什么我最初的尝试没有成功?

4

12 回答 12

295

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

您的问题似乎不需要使用类的类型参数。如果您更详细地描述您正在尝试做的事情,也许我们可以帮助您找到更好的方法来做到这一点。

于 2009-06-01T21:43:37.347 回答
152

T在您实例化一个类型之前,Java 不知道是什么。

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

另一种处理方式是将类型参数放在方法本身中:

static <U> void doIt(U object)

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

于 2009-06-01T19:41:18.950 回答
53

我遇到了同样的问题。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
}
于 2011-10-25T13:50:00.207 回答
22

我认为这种语法还没有被提及(如果你想要一个没有参数的方法):

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

和电话:

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

希望这对某人有所帮助。

于 2016-04-22T13:05:31.440 回答
16

在声明方法时,可以使用泛型方法的语法来做你想做的事情doIt()(注意在方法签名中添加了<T>betweenstatic和):voiddoIt()

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

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

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

于 2012-05-13T09:25:44.270 回答
6

错误中正确提到了它:您不能对非静态类型 T 进行静态引用。原因是类型参数T可以被任何类型参数替换,例如Clazz<String>Clazz<integer>。但是静态字段/方法由所有非静态类型共享- 类的静态对象。

以下摘录摘自文档

类的静态字段是类的所有非静态对象共享的类级变量。因此,不允许使用类型参数的静态字段。考虑以下类:

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的实际类型是什么?它不能同时是智能手机、寻呼机和平板电脑。因此,您不能创建类型参数的静态字段。

正如克里斯在他的回答中正确指出的那样,在这种情况下,您需要将类型参数与方法一起使用,而不是与类一起使用。你可以这样写:

static <E> void doIt(E object) 
于 2015-10-23T10:13:11.593 回答
3

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

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());
    }
}
于 2012-05-10T07:21:07.343 回答
3

由于静态变量由类的所有实例共享。例如,如果您有以下代码

class Class<T> {
  static void doIt(T object) {
    // using T here 
  }
}

T 仅在创建实例后可用。但是静态方法甚至可以在实例可用之前使用。因此,不能在静态方法和变量中引用泛型类型参数

于 2018-07-16T09:59:15.990 回答
2

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

泛型就像 C++ 中的模板一样工作,因此您应该首先实例化您的类,然后使用指定类型的函数。

于 2009-06-01T19:43:23.687 回答
1

简而言之,它的发生是因为泛型的“擦除”属性。这意味着虽然我们定义了ArrayList<Integer>and ArrayList<String>,但在编译时它仍然是两种不同的具体类型,但在运行时 JVM 会擦除泛型类型和只创建一个 ArrayList 类而不是两个类。因此,当我们为泛型定义静态类型方法或任何东西时,它由该泛型的所有实例共享,在我的示例中,它由ArrayList<Integer>和共享。这ArrayList<String>就是你得到错误的原因。类的泛型类型参数不是允许在静态上下文中!

于 2016-05-04T02:00:41.843 回答
1

@BD at 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";
      }
}
于 2017-10-12T16:06:37.550 回答
0

T 不在静态方法的范围内,因此您不能在静态方法中使用 T 。您需要为静态方法定义不同的类型参数。我会这样写:

class Clazz<T> {

  static <U> void doIt(U object) {
    // ...
  }

}

例如:

public class Tuple<T> {

    private T[] elements;

    public static <E> Tuple<E> of(E ...args){
        if (args.length == 0) 
             return new Tuple<E>();
        return new Tuple<E>(args);
    }

    //other methods
}
于 2021-12-16T23:15:36.357 回答