210

In Java, I'd like to have something as:

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?

4

12 に答える 12

295

静的メソッドまたは静的フィールドでクラスのジェネリック型パラメーターを使用することはできません。クラスの型パラメーターは、インスタンスメソッドとインスタンスフィールドのスコープ内にのみあります。静的フィールドと静的メソッドの場合、それらはクラスのすべてのインスタンス間で共有されます。異なる型パラメーターのインスタンスであっても、明らかに特定の型パラメーターに依存することはできません。

問題がクラスのtypeパラメーターを使用する必要があるとは思われません。あなたがやろうとしていることをより詳細に説明すれば、おそらく私たちはあなたがそれを行うためのより良い方法を見つけるのを手伝うことができます。

于 2009-06-01T21:43:37.347 に答える
152

Tタイプをインスタンス化するまで、Javaは何であるかを知りません。

呼び出すことで静的メソッドを実行できるかもしれませんが、実行Clazz<T>.doit(something)できないようです。

物事を処理するもう1つの方法は、typeパラメーターをメソッド自体に配置することです。

static <U> void doIt(U object)

これでは、Uに対する適切な制限は得られませんが、何もないよりはましです。

于 2009-06-01T19:41:18.950 に答える
53

私はこれと同じ問題に遭遇しました。Collections.sortJavaフレームワークでのソースコードをダウンロードして答えを見つけました。私が使用した答えは<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>staticvoiddoIt()

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' !!!

于 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は電話、ポケットベル、およびPCで共有されるため、実際のosのタイプは何ですか。スマートフォン、ポケットベル、タブレットPCを同時に使用することはできません。したがって、タイプパラメータの静的フィールドを作成することはできません。

chrisが彼の回答で正しく指摘しているように、この場合はクラスではなく、メソッドでtypeパラメーターを使用する必要があります。あなたはそれを次のように書くことができます:

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>しますArrayList<String>が、コンパイル時には2つの異なる具象型として残りますが、実行時にJVMはジェネリック型を消去します。 2つのクラスではなく1つの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()
                       + "' !!!");
  }
// ...
}

Ok。しかし、元の問題に戻りましょう。クラス宣言の最初の型変数は冗長です。メソッドの2番目のものだけが必要です。ここでもう一度行きますが、それはまだ最終的な答えではありません:

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 に答える