10

開発者が非汎用 API を操作すると、通常、「チェックされていない」警告が表示されます。次の例を検討してください。

import java.util.AbstractList;

import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class IterableNodeList<T extends Node> extends AbstractList<T>
{
    private NodeList list;

    public IterableNodeList(NodeList list)
    {
        this.list = list;
    }

    public T get(int index)
    {
        return (T)this.list.item(index);
    }

    public int size()
    {
        return this.list.getLength();
    }
}

もちろん、警告がないようにこれを書く努力をすることもできます:Tクラスの型パラメーターとコンストラクター引数を使用し、メンバー変数と呼び出しClass<T>を一致させます。cast()

別の方法として、IDE 構成とビルド スクリプト (Maven POM など) を編集して、このコンパイラ警告を完全に無効にすることも考えられます。これを行った場合、コードはそのままになる可能性がありますが、それには欠点があるに違いないと確信しています。ただし、合理的で現実的な例は思いつきません。

  • @SuppressWarningsこの警告は、「ここに固執する、とにかく他に選択肢がない」よりも価値があります。
  • 結果のコードは実際には、警告を無視 (無効) した場合とは異なる (より安全な) 動作をします。

そのような例を考えたり、これらの「チェックされていない」警告をグローバルに無効にすることが悪い考えである別の理由を挙げたりできますか? それとも実際に良い考えですか?

アップデート

前の例は、実際には警告を引き起こしませんでした。いくつかの答えは、もはや意味がありません。ご不便おかけしてすみません。

4

3 に答える 3

5

Item 24ofによると、特にこのアノテーションをクラス全体に適用する場合はEffective Java 2nd Edition、広く頻繁に使用することは一般的に悪い考えです。@SupressWarningsClassCastException

ArrayListただし、のtoArrayメソッドの実装など、場合によっては役立つことがあります。

@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
    if (a.length < size)
        // Make a new array of a's runtime type, but my contents:
        return (T[]) Arrays.copyOf(elementData, size, a.getClass());
    System.arraycopy(elementData, 0, a, 0, size);
    if (a.length > size)
        a[size] = null;
    return a;
}
于 2013-02-05T12:23:03.593 に答える
2

2番目の例では、私の日食でコンパイラの警告が発生することはありません。また、そうすべき理由を考えることもできません。したがって、それは私の好ましい解決策です。

チェックされていない警告が存在する理由は、それらを無視するとヒープ汚染を引き起こす可能性があるためです。

通常のキャストがチェックされます。つまりClassCastException、値が目的のタイプと互換性がない場合は、結果になります。チェックされていないキャストは、それを保証するものではありません。つまり、値が適切なタイプでなくても成功する可能性があります。これにより、宣言されたタイプのサブタイプではない値を保持する変数が発生する可能性があります。これは、Java仕様で「ヒープ汚染」と呼ばれる条件です。ランタイム型システムの整合性を確保するために、Javaコンパイラは、ジェネリック型の変数が使用されるたびに通常のキャストを挿入します。ヒープ汚染が存在する場合、これらのキャストは失敗する可能性があります。

たとえば、プログラム:

static void appendTo(List list) {
    list.add(1); // unchecked warning
}

static void printLengths(List<String> strings) {
    for (String s : strings) { // throws ClassCastException
        System.out.println(s.length());
    }
}

public static void main(String[] args) throws Exception {
    List<String> strings = new ArrayList<>();
    strings.add("hello");
    appendTo(strings);
    printLengths(strings);
}

ClassCastExceptionソースコードにキャストが含まれていない行にをスローします。これは、ほとんどのプログラマーをひどく混乱させる可能性があります。

そのため、非ジェネリックキャスト、または(ジェネリックコードでは)リフレクティブキャストのいずれかで、可能な限りチェックキャストを使用することをお勧めします。

class Habitat<T> {
    private final Class<T> clazz;

    private List<T> inhabitants;

    void add(Object o) {
        inhabitants.add(clazz.cast(o));
    }
}
于 2013-02-05T12:38:11.837 に答える
2

有効な Java 2nd Editionから:

アノテーションはSuppressWarnings、個々のローカル変数宣言からクラス全体まで、あらゆる粒度で使用できます。注釈は常に可能な限り最小の範囲で使用してSuppressWarningsください。通常、これは変数宣言か、非常に短いメソッドまたはコンストラクターになります。SuppressWarningsクラス全体で使用しないでください。これを行うと、重大な警告が隠される可能性があります。

SuppressWarnings複数行の長さのメソッドまたはコンストラクターで注釈を使用していることに気付いた場合は、それをローカル変数宣言に移動できる場合があります。新しいローカル変数を宣言する必要があるかもしれませんが、その価値はあります。

SuppressWarnings宣言ではないため、return ステートメントに注釈を付けることは違法です[JLS、9.7]。メソッド全体に注釈を付けたくなるかもしれませんが、そうしないでください。代わりに、ローカル変数を宣言して戻り値を保持し、その宣言に注釈を付けます

于 2013-02-08T14:22:08.507 に答える