7

タイプ T のいくつかの要素のコンテナー (リスト) があり、それをフィルター処理したいと考えています。したがって、特定のサブタイプ U の要素のみが含まれています。「動的な」戻り値の型を設定することは可能でしょうか?

例:

class SomeContainer<T> extends ArrayList<T>{

    public SomeContainer<T> subset(Class c){
        SomeContainer<...here the type of c > output = new SomeContainer<.. also ..>();

        //filter own elements and only add c-objects in the new list

        return output;
    }
}

現時点では、c-Class-type (T のサブタイプ) ではなく、ジェネリック型 T のリストを返します。したがって、次のコンパイラ通知を受け取ることがあります。

Note: SomeContainer.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.

サブタイプのオブジェクトの後にリストをフィルタリングし、サブタイプ固有のメソッドをトリガーしたいので、特定のサブタイプ リストが必要になります。

4

3 に答える 3

9

java.lang.Classそれ自体でパラメーター化されたジェネリック型であるため、次のようにその型パラメーターを使用できます。

public <U extends T> SomeContainer<U> subset(Class<U> c){
    SomeContainer<U> output = new SomeContainer<U>();
    for (T val : this) {
        if (c.isInstance(val)) {
            output.add(c.cast(val));
        }
    }
    return output;
}
于 2012-10-14T11:44:18.790 に答える
1

ジェネリックはコンパイル時のアーティファクトのみであるため、スキームは機能しません。コンパイラは、この関数を呼び出すコード行を実行するたびに、どのクラスが必要になるかを予測できません。クラスリテラルのみを使用して関数を呼び出すような非常に制約があり、まったく役に立たない場合を除き、このソリューションをタイプセーフにすることはできません。ただし、それは、あなたが述べたように、動的であるという目的をほぼ確実に無効にします。

于 2012-10-14T11:46:59.967 に答える
0

最初のポイント:Class c引数をに置き換えることで、チェックされていない操作の警告を削除できますClass<T> c。それはあなたが必要とするすべてかもしれません...その場合... =:-)

2 番目のポイント: 通常、 SomeContainer.subset() を呼び出すコードは、コンパイル時に (ロジック コンテキストから) タイプ U を認識します。そうでなければ、Class c引数を渡すことができません。

試す:

class SomeContainer<T> extends ArrayList<T>{

    public <U extends T> SomeContainer subset(Class<U> c){
        SomeContainer<U> output = new SomeContainer<U>();  
        // put filtered elements into output

        return output;    
    }
}

私がそこで何をしたか見てください。
メソッド呼び出しに 2 番目のタイプ パラメータを導入しました: U extends T。との引数でもこれを使用しましたClass<U> c
呼び出し元は次のように呼び出します (ここで、X は T のサブクラスとして選択されます)。

SomeContainer<X> mySubset = mySomeContainer.subset(X.class);     // type inference
SomeContainer<X> mySubset = mySomeContainer.<X>subset(X.class);  // type arg specified 


これよりも動的なものが必要な場合は、ワイルドカードが役立ちます。パラメーター化された型の「ファミリー」を入出力できるようにします。

public SomeContainer<? extends X> subset(Class<? extends X> c){

これは「プラスチック」関数インターフェイスです。T のサブクラスである任意の X に対してSomeContainer<T>orを返すことができます。以下も機能します。SomeContainer<X>

public SomeContainer<? super Z> subset(Class<? extends X> c){

ただし、別のポスターが言ったように、ジェネリックはコンパイル時の構造であり、コンパイル中に生成された非ジェネリック コードに置き換えられます。つまり、1 行のコードでジェネリック型をインスタンス化するために使用する型を動的に決定することはできません。ただし、少しごまかすことができます。T のサブクラスの数が限られている場合、たとえば X、Y、Z のように、Z が Y を拡張し、Y が Z を拡張する場合、古き良きハッキーな「if ステートメント」を使用できます。試す:

class SomeContainer extends ArrayList{

public SomeContainer<? extends X> subset(Class<? extends X> c){
    SomeContainer<? extends X> output = null;

    // would like to use:  "if (c instance of Class<Z>)"
    // but instanceof does not allow generic type arguments
    if (c.getName().equals(Z.class.getName())) {
        SomeContainer<Z> outputZ = new SomeContainer<Z>();
        // put filtered elements into outputZ
        output = outputZ;
    } else if (c.getName().equals(Y.class.getName())) {
        SomeContainer<Y> outputY = new SomeContainer<Y>();
        // put filtered elements into outputZ
        output = outputY;
    } else if (c.getName().equals(X.class.getName())) {
        SomeContainer<X> outputX = new SomeContainer<X>();
        // put filtered elements into outputZ
        output = outputX;
    }
    return output;    
}

}

簡単!(またはしない) =:-)

于 2012-10-15T05:32:30.130 に答える