Javaでは、次のようなものが欲しいです。
class Clazz<T> {
static void doIt(T object) {
// shake that booty
}
}
しかし、私は得る
非静的型Tへの静的参照を作成できません
基本的な使用法以外にジェネリックを理解していないため、その意味を理解することはできません。主題に関する多くの情報をインターネットで見つけることができなかったのは助けにはなりません。
同様の方法で、そのような使用が可能かどうかを誰かが明確にできますか?また、最初の試みが失敗したのはなぜですか?
クラスのジェネリック型パラメーターを静的メソッドまたは静的フィールドで使用することはできません。クラスの型パラメーターは、インスタンスメソッドとインスタンスフィールドのスコープ内にのみあります。静的フィールドと静的メソッドの場合、それらはクラスのすべてのインスタンス間で共有され、異なる型パラメーターのインスタンス間でも共有されるため、明らかに特定の型パラメーターに依存することはできません。
クラスのtypeパラメータを使用する必要があるとは思われません。あなたがしようとしていることをより詳細に説明するなら、私たちはあなたがそれをするより良い方法を見つけるのを助けるかもしれません。
Javaは、型をインスタンス化するまで、T
が何であるかを知りません。
Clazz<T>.doit(something)
を呼び出して静的メソッドを実行することもできますが、できないようです。
物事を処理する他の方法は、メソッド自体にtypeパラメーターを入れることです:
static <U> void doIt(U object)
これはUに対する適切な制限を取得しませんが、何もしないよりはましです。
私はこの同じ問題に出くわしました。 JavaフレームワークでCollections.sort
のソースコードをダウンロードすることで、答えを見つけました。私が使用した答えは、クラス定義ではなくメソッドに<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
}
doIt()
メソッドを宣言するときにジェネリックメソッドの構文を使用することにより、目的の処理を実行できます(メソッドシグネチャでstatic
とvoid
の間に<T>
が追加されていることに注意してくださいdoIt()
):
class Clazz<T> {
static <T> void doIt(T object) {
// shake that booty
}
}
上記のコードをCannot make a static reference to the non-static type T
エラーなしで受け入れるようにEclipseエディターを取得し、それを次の作業プログラムに拡張しました(ある程度年齢に適した文化的参照で完了します)。
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」!!!
この構文はまだ言及されていないと思います(引数のないメソッドが必要な場合):
class Clazz {
static <T> T doIt() {
// shake that booty
}
}
そして呼び出し:
String str = Clazz.<String>doIt();
これが誰かを助けることを願っています。
他の人はすでにあなたの質問に答えていますが、それに加えて、O'Reilly Java Generics の本を完全に再コメントできます。それは時々微妙で複雑な主題であり、しばしば無意味な制限があるように思えますが、本はJavaジェネリックがそうである理由を説明するかなり良い仕事をします。
次のような何かがあなたを近づけます
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++のテンプレートのように機能するため、最初にクラスをインスタンス化してから、指定された型で関数を使用する必要があります。
@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";
}
}
また、簡単に言えば、ジェネリックの「消去」プロパティのために発生します。これは、ArrayList<Integer>
とArrayList<String>
を定義しますが、コンパイル時には2つの異なる具体的な型のままであることを意味します。ただし、実行時にJVMはジェネリック型を消去し、2つのクラスではなく1つのArrayListクラスのみを作成します。したがって、ジェネリックの静的型メソッドまたは何かを定義すると、そのジェネリックのすべてのインスタンスで共有されます。私の例では、ArrayList<Integer>
とArrayList<String>
の両方で共有されます。そのため、エラーが発生しますクラスのジェネリック型パラメーターは静的コンテキストでは許可されていません!
静的変数はクラスのすべてのインスタンスで共有されるため。たとえば、次のコードがある場合
class Class<T> {
static void doIt(T object) {
// using T here
}
}
Tは、インスタンスが作成された後にのみ使用可能です。ただし、インスタンスが使用可能になる前でも静的メソッドを使用できます。そのため、ジェネリック型パラメーターは静的メソッドおよび変数内で参照できません