JavaでClass <T>を使用する方法


247

Genericsと、この質問で背後で実際に何が行われるかについての良い議論があります。そのため、これVector<int[]>は整数配列のベクトルでHashTable<String, Person>あり、キーが文字列と値であるテーブルですPerson。しかし、私を困らせるのはの使用法ですClass<>

javaクラスClassはテンプレート名も受け取ることになっています(または、Eclipseの黄色い下線が表示されます)。何を入れればいいのか分かりません。Classオブジェクトの要点は、反射などのために、オブジェクトに関する情報が完全にない場合です。Classオブジェクトが保持するクラスを指定するのはなぜですか?はっきりとわからない、またはClassオブジェクトを使用しない、特定のオブジェクトを使用する。

回答:


136

クラスClassの生成バージョンを使用すると、とりわけ、次のような記述が可能になります。

Class<? extends Collection> someCollectionClass = someMethod();

そして、受け取るClassオブジェクトがextends Collectionであり、このクラスのインスタンスが(少なくとも)Collectionになることを確認できます。


183

私たちが知っているのは、「任意のクラスのすべてのインスタンスが、そのタイプのクラスの同じjava.lang.Classオブジェクトを共有している」ということだけです。

例えば)

Student a = new Student();
Student b = new Student();

その後a.getClass() == b.getClass()、本当です。

今仮定します

Teacher t = new Teacher();

ジェネリックなしでは以下が可能です。

Class studentClassRef = t.getClass();

しかし、これは今間違っています..?

例)public void printStudentClassInfo(Class studentClassRef) {}で呼び出すことができますTeacher.class

これはジェネリックを使用して回避できます。

Class<Student> studentClassRef = t.getClass(); //Compilation error.

Tとは何ですか?Tは型パラメーター(型変数とも呼ばれます)です。山かっこ(<>)で区切られ、クラス名の後に続きます。
Tは単なる記号であり、クラスファイルの書き込み中に宣言された変数名(任意の名前)と同様です。その後、Tは
初期化中に有効なクラス名に置き換えられます(HashMap<String> map = new HashMap<String>();

例えば) class name<T1, T2, ..., Tn>

したがってClass<T>、特定のクラスタイプ ' T'のクラスオブジェクトを表します。

クラスメソッドが以下のような不明な型パラメーターで機能する必要があると仮定します

/**
 * Generic version of the Car class.
 * @param <T> the type of the value
 */
public class Car<T> {
    // T stands for "Type"
    private T t;

    public void set(T t) { this.t = t; }
    public T get() { return t; }
}

ここでは、T StringCarNameとしてタイプとして使用できます。

OR Tは、IntegertypeとしてmodelNumberとして使用できます。

OR TはObject有効な車のインスタンスとしてタイプとして使用できます

ここで、上記は実行時に別の方法で使用できる単純なPOJOです。
コレクション例)リスト、セット、ハッシュマップは、Tの宣言に従ってさまざまなオブジェクトで機能する最良の例ですが、Tを文字列として宣言 すると、
例)HashMap<String> map = new HashMap<String>();それは文字列クラスインスタンスオブジェクトのみを受け入れます。

ジェネリックメソッド

ジェネリックメソッドは、独自の型パラメーターを導入するメソッドです。これはジェネリック型の宣言と似ていますが、型パラメーターのスコープは、それが宣言されているメソッドに限定されます。静的および非静的なジェネリックメソッド、およびジェネリッククラスコンストラクターを使用できます。

ジェネリックメソッドの構文には、山かっこで囲まれた型パラメーターが含まれ、メソッドの戻り型の前に表示されます。ジェネリックメソッドの場合、型パラメーターセクションは、メソッドの戻り型の前に指定する必要があります。

 class Util {
    // Generic static method
    public static <K, V, Z, Y> boolean compare(Pair<K, V> p1, Pair<Z, Y> p2) {
        return p1.getKey().equals(p2.getKey()) &&
               p1.getValue().equals(p2.getValue());
    }
}

 class Pair<K, V> {

    private K key;
    private V value;
}

<K, V, Z, Y>メソッドの引数で使用される型の宣言は、ここにある戻り型の前にありbooleanます。

以下で; 型宣言<T>はクラスレベルで既に宣言されているため、メソッドレベルでは必要ありません。

class MyClass<T> {
   private  T myMethod(T a){
       return  a;
   }
}

ただし、クラスレベルの型パラメーターK、V、Z、Yは静的コンテキスト(ここでは静的メソッド)で使用できないため、以下は誤りです。

class Util <K, V, Z, Y>{
    // Generic static method
    public static  boolean compare(Pair<K, V> p1, Pair<Z, Y> p2) {
        return p1.getKey().equals(p2.getKey()) &&
               p1.getValue().equals(p2.getValue());
    }
}

その他の有効なシナリオは

class MyClass<T> {

        //Type declaration <T> already done at class level
        private  T myMethod(T a){
            return  a;
        }

        //<T> is overriding the T declared at Class level;
        //So There is no ClassCastException though a is not the type of T declared at MyClass<T>. 
        private <T> T myMethod1(Object a){
                return (T) a;
        }

        //Runtime ClassCastException will be thrown if a is not the type T (MyClass<T>).  
        private T myMethod1(Object a){
                return (T) a;
        }       

        // No ClassCastException        
        // MyClass<String> obj= new MyClass<String>();
        // obj.myMethod2(Integer.valueOf("1"));
        // Since type T is redefined at this method level.
        private <T> T myMethod2(T a){
            return  a;
        }

        // No ClassCastException for the below
        // MyClass<String> o= new MyClass<String>();
        // o.myMethod3(Integer.valueOf("1").getClass())
        // Since <T> is undefined within this method; 
        // And MyClass<T> don't have impact here
        private <T> T myMethod3(Class a){
            return (T) a;
        }

        // ClassCastException for o.myMethod3(Integer.valueOf("1").getClass())
        // Should be o.myMethod3(String.valueOf("1").getClass())
    private  T myMethod3(Class a){
        return (T) a;
    }


        // Class<T> a :: a is Class object of type T
        //<T> is overriding of class level type declaration; 
        private <T> Class<T> myMethod4(Class<T> a){
            return  a;
        }
    }

そして最後に、Staticメソッドは常に明示的な<T>宣言を必要とします。クラスレベルからは派生しませんClass<T>。これは、クラスレベルTがインスタンスにバインドされているためです。

ジェネリクスの制限も読む

ワイルドカードとサブタイプ

ジェネリックメソッドの型引数


2
境界ワイルドカード上の私の答えstackoverflow.com/questions/1368166/...
Kanagavelu Sugumar

"Class <T>は、特定のクラスタイプ 'T'のクラスオブジェクトを表します。ありがとう..
bynu022

この回答は、(Javaの)クラスに関する質問で(学校からの)クラスを使用する方法がひどく混乱しています。文から文へと作者が話していることを知るのは難しい。
Echox

@Echox申し訳ありませんが、具体的な質問があれば改善できます。
Kanagavelu Sugumar


32

Javaドキュメントから:

[...]さらに意外なことに、クラスClassが一般化されました。クラスリテラルは、型トークンとして機能し、実行時とコンパイル時の両方の型情報を提供します。これにより、新しいAnnotatedElementインターフェースのgetAnnotationメソッドによって例示される静的ファクトリーのスタイルが可能になります。

<T extends Annotation> T getAnnotation(Class<T> annotationType); 

これはジェネリックメソッドです。次のスニペットに示すように、引数から型パラメーターTの値を推測し、Tの適切なインスタンスを返します。

Author a = Othello.class.getAnnotation(Author.class);

ジェネリックの前に、結果をAuthorにキャストする必要がありました。また、実際のパラメーターがAnnotationのサブクラスを表していることをコンパイラーにチェックさせる方法もなかったでしょう。[...]

まあ、私はこの種のものを使用する必要はありませんでした。誰でも?


2
私は(思った)やった。私が使用した(一種の)フレームワークでは、モジュールが依存するサービスのクラス名を渡す必要があります。その上に、選択の量を制限するために、Classオブジェクトをとるレイヤーを作成しました。Class<? extends X>表記法を使用して、「サービス」タイプのみに制限できると考えました。共通の「サービス」タイプがなかったことを除いて、私はそれだけでそれを行うことができましたClass<?>。ああ。
fwielstra '18年

9

私が見つけたclass<T>私はサービスレジストリの検索を作成するときに便利。例えば

<T> T getService(Class<T> serviceClass)
{
    ...
}

5

他の回答が指摘しているように、これclassが一般化された理由はたくさんあります。ただし、で使用するジェネリック型を知る方法がない場合がたくさんありますClass<T>。これらの場合、黄色の日食警告を単に無視するか、または使用することができますClass<?>...それが私がそれをする方法です;)


@SuppressWarnings("unchecked")救助に来る!(コードの潜在的な問題を不明瞭にないように、できるだけ小さいスコープに常に適用するように注意してください。)
Donal Fellows

4

@Kire Haglinの回答に続いて、ジェネリックメソッドのさらなる例をJAXB非整列化のドキュメントで見ることができます。

public <T> T unmarshal( Class<T> docClass, InputStream inputStream )
         throws JAXBException {
  String packageName = docClass.getPackage().getName();
  JAXBContext jc = JAXBContext.newInstance( packageName );
  Unmarshaller u = jc.createUnmarshaller();
  JAXBElement<T> doc = (JAXBElement<T>)u.unmarshal( inputStream );
  return doc.getValue();
}

これによりunmarshal、任意のJAXBコンテンツツリータイプのドキュメントを返すことができます。


2

でワイルドカードを使用することがよくありClassます。たとえば、Class<? extends JComponent>では、クラスがのサブクラスであることを指定できますJComponentClassからインスタンスを取得した場合はClass.forName、を使用Class.asSubclassして、たとえばインスタンスを構築する前にキャストを実行できます。


2

Javaでは<T>、ジェネリッククラスを意味します。ジェネリッククラスは、任意のタイプのデータ型機能するクラスです。つまり、データ型に依存しないと言えます。

public class Shape<T> {
    // T stands for "Type"
    private T t;

    public void set(T t) { this.t = t; }
    public T get() { return t; }
}

どこTは、タイプを意味します。次に、このShapeクラスのインスタンスを作成するときに、これが機能するデータ型をコンパイラーに通知する必要があります。

例:

Shape<Integer> s1 = new Shape();
Shape<String> s2 = new Shape();

整数は型であり、文字列も型です。

<T>具体的にはジェネリック型を表します。Java Docsによれば-ジェネリック型は、型でパラメーター化されたジェネリッククラスまたはインターフェースです。


0

別の例を示すと、クラス(Class<T>)の汎用バージョンでは、以下のような汎用関数を記述できます。

public static <T extends Enum<T>>Optional<T> optionalFromString(
        @NotNull Class<T> clazz,
        String name
) {
    return Optional<T> opt = Optional.ofNullable(name)
            .map(String::trim)
            .filter(StringUtils::isNotBlank)
            .map(String::toUpperCase)
            .flatMap(n -> {
                try {
                    return Optional.of(Enum.valueOf(clazz, n));
                } catch (Exception e) {
                    return Optional.empty();
                }
            });
}

-2

最初は混乱します。しかし、それは以下の状況で役立ちます:

class SomeAction implements Action {
}

// Later in the code.
Class<Action> actionClass = Class.forName("SomeAction"); 
Action action = actionClass.newInstance();
// Notice you get an Action instance, there was no need to cast.

4
それは、Action a = new Action()と言う非常に複雑な方法ではありませんか?
Karl

1
Action a = new Action() Action私はインターフェースSomeActionです。インスタンスを取得しようとしているのです。SomeAction実行時に使用できるのは名前のみです。
fastcodejava 2010

これは型チェックに合格しません。Javaコンパイラは<code> Class.forName( "SomeAction")</ code>が<code> Class <Action> </ code>型であることを通知する方法がないため、これは実行時に既知である。
tonio 2010年

@tonio、そうですね、そのため、おそらく最初の行を何らかのtry / catchでラップする必要があります。ただし、例外がスローされないと仮定すると、2行目は動作することが保証されています。
MatrixFrog

2
あなたが本当に説明しているのは、SomeAction.classがパターンClass <?に一致するということです。extends Action>-つまり、メソッドuseAction(Class <?extends Action> klass)がある場合、useAction(SomeAction.class)を呼び出すことができます。
Thomas Andrews、

-5

ビーフクラスを使用するだけです。

public <T> T beefmarshal( Class<beef> beefClass, InputBeef inputBeef )
     throws JAXBException {
     String packageName = docClass.getPackage().getBeef();
     JAXBContext beef = JAXBContext.newInstance( packageName );
     Unmarshaller u = beef.createBeef();
     JAXBElement<T> doc = (JAXBElement<T>)u.beefmarshal( inputBeef );
     return doc.getBeef();
}

4
これは実際には質問に対する完全な答えを提供しません。追加する必要があると思われる場合は、この回答を編集してください。
MasterAM 2013
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.