2

これが私のコードです:

public class ArrayTaskList<E> {
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        ArrayTaskList<E> other = (ArrayTaskList<E>) obj;
        if (!Arrays.equals(db, other.db))
            return false;
        return true;
    }
}

そしてコンパイラは言う:

型の安全性: オブジェクトから arraytasklist へのチェックされていないキャスト

私はそれが警告であることを理解していますが、このコードを試しても警告はありません:

ArrayTaskList<?> other = (ArrayTaskList<?>) obj;

より便利なソリューションですか?

4

4 に答える 4

4

違いは、未加工の型オブジェクトは型安全ではなく、無制限のワイルドカードは型安全を提供することです。

たとえば、生の型を使用すると、次のようなコードを作成できます。

List list = new ArrayList<String>();
list.add(42); // integer
list.add(true); // boolean
list.add(whateverYouWant); // whatever you want

このコードの間:

List<?> list2 = new ArrayList<String>();
list2.add(42);
list2.add(true);

コンパイラ エラーが発生します。

于 2013-10-01T15:26:33.403 に答える
0

obj実行がその行に到達すると、それが のインスタンスであることがわかりますArrayTaskListArrayTaskList<Integer>ただし、それがorArrayTaskList<String>などであるかどうかはわかりません。

したがって、キャストは警告を生成します ( to をキャストしようとすることができますArrayTaskList<Integer>) ArrayTaskList<String>

ただし、ここでは型情報は必要ないため、ここでは使用ArrayTaskList<?>する方が実際にはより良い解決策になります。

編集

タイプの境界を使用しても警告が発生するため、ここで誤解がありました。@svz が指摘したように、ArrayTaskList<?>仮定を追加せず、型チェックを有効にするだけです。

コンパイラは、へのキャストが問題ないことを信頼しますが、型もArrayTaskListあると仮定しているため、警告が生成されます。コンパイラはそれをチェックできないため、警告が発行されます。またはを使用すると、コンパイラは型を無視しますが、失敗する可能性のあるメソッドが呼び出されるとエラーが発生します。objE<?><? extends XYZ>

次の例を検討してください。

あなたのクラスは、したがって、またはArrayTaskList<E extends Number>にキャストします(たとえば、どこにある可能性があります)。ArrayTaskList<Number>ArrayTaskList<E>ELong

Eその場合、コンパイラは が などのタイプNumberであるかどうかを認識しないLongため、警告が表示されます。これobjは、ArrayTaskList<Double>と をキャストするとArrayTaskList<Number>、Long を Double (痛い) のリストに追加できるためです。

したがって、コンパイラはそのキャストについて警告します。

にキャストするArrayTaskList<?>と、型を無視するようにコンパイラーに指示されますが、 を呼び出した場合はエラーが発生other.add(...)し、偶発的な不一致を防ぐことができます。

編集2:

Eここにはまだいくつかの誤解があります (これについては後で考えます) が、これまでのところ、警告なしでキャストし、提供される可能性のある上限を引き続き使用する方法を次に示します。

public boolean equals(Object obj) {
  ...      
  return equals_((ArrayTaskList<?>)obj);
}

protected boolean equals_(ArrayTaskList<? extends Number> other)
{      
  if (!Arrays.equals(db, other.db))
        return false;
  return true;
}
于 2013-10-01T15:18:35.117 に答える
0

代わりに次の実装を使用できます。

@Override
public boolean equals(Object obj) {
    return obj instanceof ArrayTaskList && obj.hashCode() == hashCode();
}

@Override
public int hashCode() {
    return Arrays.hashCode(db);
}

そうすれば、チェックされていないキャストの問題はもうありません;)

ただし、型消去のため、

new ArrayTaskList<String>().equals(new ArrayTaskList<Integer>())

一方がクラスパラメータとして使用されている間にもう一方が使用されていてもtrue、両方が同じdb配列を持っている場合は返されます。StringInteger

于 2013-10-01T15:29:19.453 に答える
0

ArrayTaskListコンストラクターに inscance を渡すこともできます。Class<E> clazzその後、キャストを実行できますclazz.cast(...)

public class ArrayTaskList<E> {
    Class<ArrayTaskList<E>> clazz;

    public ArrayTaskList(Class<ArrayTaskList<E>> c) {
        clazz = c;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        ArrayTaskList<E> other = clazz.cast(obj);
        if (!Arrays.equals(db, other.db))
            return false;
        return true;
    }
}
于 2013-10-01T15:27:23.413 に答える