回答:
静的メソッドまたは静的フィールドでクラスのジェネリック型パラメーターを使用することはできません。クラスの型パラメーターは、インスタンスメソッドとインスタンスフィールドのスコープ内にのみあります。静的フィールドと静的メソッドの場合、それらはクラスのすべてのインスタンス間で共有され、異なる型パラメーターのインスタンスであっても、特定の型パラメーターに依存することはできません。
あなたの問題がクラスの型パラメーターを使用する必要があるべきではないようです。あなたがやろうとしていることをより詳細に説明するなら、多分私たちはあなたがそれを行うためのより良い方法を見つけるのを助けることができます。
JavaはT
、型をインスタンス化するまでは何であるかを認識しません。
呼び出しによって静的メソッドを実行できるかもしれませんがClazz<T>.doit(something)
、それはできないようです。
処理するもう1つの方法は、メソッド自体に型パラメーターを配置することです。
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
でフィールドをマスクするのと同じ方法で、1つ目をマスクします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フィールド/メソッドは、すべての非によって共有されています-クラスの静的オブジェクト。
次の抜粋は、ドキュメントから抜粋したものです。
クラスの静的フィールドは、クラスのすべての非静的オブジェクトによって共有されるクラスレベルの変数です。したがって、型パラメーターの静的フィールドは許可されません。次のクラスを考えてみましょう:
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を同時に使用することはできません。したがって、型パラメーターの静的フィールドを作成することはできません。
クリスが彼の回答で正しく指摘したように、この場合はクラスではなくメソッドで型パラメーターを使用する必要があります。あなたはそれを次のように書くことができます:
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>
、コンパイル時に2つの異なる具象型のままですが、実行時にJVMがジェネリック型と2つのクラスではなく、1つのArrayListクラスのみを作成します。したがって、静的型メソッドまたはジェネリックの何かを定義すると、そのジェネリックのすべてのインスタンスで共有されます。この例では、両方ArrayList<Integer>
で共有されていArrayList<String>
ます。そのため、エラーが発生します。クラスのジェネリック型パラメーターは静的コンテキストで許可されています!
@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";
}
}