Java Genericメソッドを静的にする方法は?


172

以下は、Javaジェネリッククラスを作成して配列に単一の項目を追加する方法のスニペットです。appendToArrayを静的メソッドにするにはどうすればよいですか。メソッドシグネチャにstaticを追加すると、コンパイルエラーが発生します。

public class ArrayUtils<E> {

        public E[] appendToArray(E[] array, E item) {
            E[] result = (E[])new Object[array.length+1];
            result[array.length] = item;
            return result;
        }
}

どのようなコンパイルエラーが発生しますか?また、なぜ標準ライブラリコンテナの1つだけを使用しないのですか?
Karl Knechtel、2010

1
コンパイルエラー:実際にはstatic修飾子を誤って追加しました。
Chris Johnson

(EVIL)リフレクションを使用して、クライアントコードが例外をスローしないようにする必要があることに注意してください。参照配列は避けることをお勧めします。
トム・ホーティン-

回答:


283

あなたができる唯一のことはあなたの署名をに変えることです

public static <E> E[] appendToArray(E[] array, E item)

重要な詳細:

戻り値の前にあるジェネリック式は、常に新しいジェネリック型変数を導入(宣言)します。

さらに、型(ArrayUtils)と静的メソッド(appendToArray)の間の型変数が互いに干渉することはありません。

だから、これはどういう意味ですか:私の答えで<E>は、メソッドがそうでない場合、Efrom を非表示にしArrayUtils<E>ますstatic。AND <E>Efrom とは関係ありませんArrayUtils<E>

この事実をよりよく反映するには、より正しい答えは次のようになります。

public static <I> I[] appendToArray(I[] array, I item)

30
また、クラスレベルの型変数Eと静的メソッドの型変数との間にはまったく関係がないことに注意してくださいE。ジェネリックメソッドを静的クラスなどのジェネリッククラス内で宣言する場合は、別の変数名を使用する方がはるかに良い方法だと思います。
メンタル裁判官、2013年

しかし、この場合、異なるタイプの1つのオブジェクトをparamsに渡すことができます。Integer []配列を最初のパラメーターとDoubleアイテムとして渡すことができるように。
pinkpanther

pinkpanther:Trueですが、静的メソッドはパラメーターを介して渡された配列オブジェクトでのみ動作するため、その要素には正しい型が必ずあるため、害はありません。
ダブラー

80
public static <E> E[] appendToArray(E[] array, E item) { ...

に注意してください<E>

静的ジェネリックメソッドにpublic static <E>は、クラスのジェネリック宣言(public class ArrayUtils<E>)とは別に独自のジェネリック宣言()が必要です。

コンパイラが静的ジェネリックメソッドの呼び出しで型のあいまいさについて不平を言っている場合(これもおそらくそうではありませんが、一般的に言えば、念のためです_class_.<_generictypeparams_>_methodname_)、特定の型を使用して静的ジェネリックメソッドを明示的に呼び出す方法は次のとおりです():

String[] newStrings = ArrayUtils.<String>appendToArray(strings, "another string");

これは、たとえばジェネリック型がメソッドの引数に関連していないために、コンパイラがジェネリック型を決定できない場合にのみ発生します。


10

型パラメーターをメソッドレベルに移動して、ジェネリッククラスではなくジェネリックメソッドがあることを示す必要があります。

public class ArrayUtils {
    public static <T> E[] appendToArray(E[] array, E item) {
        E[] result = (E[])new Object[array.length+1];
        result[array.length] = item;
        return result;
    }
}

1
ジェネリック型Eを定義していないため、これは機能しません。この場合でも、クラス定義にジェネリック型<E>が必要です。
George Xavier

0

簡単に説明します。

クラスレベルで定義されたジェネリックは、(静的)メソッドレベルで定義されたジェネリックとは完全に異なります。

class Greet<T> {

    public static <T> void sayHello(T obj) {
        System.out.println("Hello " + obj);
    }
}

上記のコードがどこかにある場合、クラスレベルで定義されたTは、静的メソッドで定義されたTとは関係がないことに注意してください。次のコードも完全に有効で、上記のコードと同等です。

class Greet<T> {

    public static <E> void sayHello(E obj) {
        System.out.println("Hello " + obj);
    }
}

静的メソッドに、クラスのジェネリックとは異なる独自のジェネリックが必要なのはなぜですか?

これは、クラスをインスタンス化することなく静的メソッドを呼び出すことができるためです。したがって、クラスがまだインスタンス化されていない場合、Tが何であるかはまだわかりません。これが、静的メソッドが独自のジェネリックを持つ必要がある理由です。

したがって、静的メソッドを呼び出すときはいつでも、

Greet.sayHello("Bob");
Greet.sayHello(123);

JVMはそれを次のように解釈します。

Greet.<String>sayHello("Bob");
Greet.<Integer>sayHello(123);

どちらも同じ出力を与えます。

Hello Bob
Hello 123
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.