155

this値のインデックスの一般的なデータ構造を調べる前に、それがパラメーター化された型のインスタンスであるかどうかを確認したいと思います。

しかし、これを行うとEclipseは文句を言います:

@Override
public int indexOf(Object arg0) {
    if (!(arg0 instanceof E)) {
        return -1;
    }

これはエラーメッセージです:

型パラメーター E に対して instanceof チェックを実行できません。ジェネリック型情報は実行時に消去されるため、代わりにその消去オブジェクトを使用してください

それを行うより良い方法は何ですか?

4

9 に答える 9

83

エラーメッセージはそれをすべて示しています。実行時に、型はなくなり、それをチェックする方法はありません。

次のようにオブジェクトのファクトリを作成することで、それをキャッチできます。

 public static <T> MyObject<T> createMyObject(Class<T> type) {
    return new MyObject<T>(type);
 }

次に、オブジェクトのコンストラクターにその型を格納します。メソッドが次のようになるように変数を設定します。

        if (arg0 != null && !(this.type.isAssignableFrom(arg0.getClass()))
        {
            return -1;
        }
于 2009-10-15T03:10:39.007 に答える
46

ジェネリックを使用した実行時の型チェックの 2 つのオプション:

オプション 1 - コンストラクターを破損する

indexOf(...) をオーバーライドしていて、コレクション全体を反復する手間を省くために、パフォーマンスのためだけに型をチェックしたいとします。

次のような不潔なコンストラクターを作成します。

public MyCollection<T>(Class<T> t) {

    this.t = t;
}

次に、isAssignableFromを使用してタイプを確認できます。

public int indexOf(Object o) {

    if (
        o != null &&

        !t.isAssignableFrom(o.getClass())

    ) return -1;

//...

オブジェクトをインスタンス化するたびに、次のことを繰り返す必要があります。

new MyCollection<Apples>(Apples.class);

もったいないと判断するかもしれません。ArrayList.indexOf(...)の実装では、型が一致することを確認しません。

オプション 2 - 失敗させます

不明な型を必要とする抽象メソッドを使用する必要がある場合、本当に必要なのは、コンパイラがinstanceofについて泣き叫ぶのをやめることだけです。このような方法がある場合:

protected abstract void abstractMethod(T element);

次のように使用できます。

public int indexOf(Object o) {

    try {

        abstractMethod((T) o);

    } catch (ClassCastException e) {

//...

コンパイラをだますためだけに、オブジェクトを T (ジェネリック型) にキャストしています。キャストは実行時に何もしませんが、抽象メソッドに間違った型のオブジェクトを渡そうとすると ClassCastException が発生します。

注 1: 抽象メソッドで未チェックのキャストを追加すると、ClassCastExceptions がここでキャッチされます。良くも悪くもなりますので、よく考えてみてください。

注 2: instanceof を使用すると、無料の null チェックが行われます。使えないので、素手でnullを確認する必要があるかもしれません。

于 2013-06-12T17:53:18.590 に答える
21

古い投稿ですが、一般的な instanceOf チェックを行う簡単な方法です。

public static <T> boolean isInstanceOf(Class<T> clazz, Class<T> targetClass) {
    return clazz.isInstance(targetClass);
}
于 2015-02-18T10:04:33.417 に答える
6

または、失敗した E へのキャストの試みをキャッチすることもできます

public int indexOf(Object arg0){
  try{
    E test=(E)arg0;
    return doStuff(test);
  }catch(ClassCastException e){
    return -1;
  }
}
于 2012-10-28T05:29:00.517 に答える
1

オブジェクトのランタイムタイプは、フィルタリングするための比較的任意の条件です。私はあなたのコレクションからそのような不器用さを遠ざけることを提案します。これは、コレクションをフィルターに委任して構造体に渡すことで簡単に実現できます。

public interface FilterObject {
     boolean isAllowed(Object obj);
}

public class FilterOptimizedList<E> implements List<E> {
     private final FilterObject filter;
     ...
     public FilterOptimizedList(FilterObject filter) {
         if (filter == null) {
             throw NullPointerException();
         }
         this.filter = filter;
     }
     ...
     public int indexOf(Object obj) {
         if (!filter.isAllows(obj)) {
              return -1;
         }
         ...
     }
     ...
}

     final List<String> longStrs = new FilterOptimizedList<String>(
         new FilterObject() { public boolean isAllowed(Object obj) {
             if (obj == null) {
                 return true;
             } else if (obj instanceof String) {
                 String str = (String)str;
                 return str.length() > = 4;
             } else {
                 return false;
             }
         }}
     );
于 2009-10-15T04:08:29.083 に答える
1

技術的にはそうする必要はありません。それがジェネリックスのポイントなので、コンパイルタイプのチェックを行うことができます。

public int indexOf(E arg0) {
   ...
}

ただし、クラス階層がある場合は、@Overrideが問題になる可能性があります。それ以外の場合は、Yishaiの回答を参照してください。

于 2009-10-15T03:13:25.363 に答える