web-dev-qa-db-ja.com

Object []をE []にキャストすることによって引き起こされる問題の例

配列にはその型に関するランタイムデータが含まれているため、E[]EはクラスFoo<E>などの汎用型パラメーターであるため、インスタンス化できません。 )、そして(E[]) new Object[n]を実行することで同じ効果を得ることができますが、それは悪いことです。そのため、コンパイラーは警告を出します。正確に何が悪いのか(有名な最後の言葉)を考えられないので、誰かがObject[]sをインスタンス化してE[]にキャストしたためにプログラムが欠陥になる例を挙げられますか?

1
Phoenix

配列がクラスの内部でのみ使用され、変数の型がE[]であるという事実がクラスの外部に公開されない(たとえば、メソッドで返される、パブリックフィールドまたは保護フィールドである、など)。 )の場合、クラスEが消去されるので問題はありません。

ただし、配列変数の型の事実をE[]としてクラスの外部に公開すると、Eの具体的な型を持つコンテキストに移動して、正しく信じることができます。彼らが得ているのはそのタイプの配列であり、その外部コードでは警告なしにClassCastExceptionをスローします。最も単純な例は、配列をE[]として単に返すメソッドであり、型パラメーターとして具象型を持つ外部コードから呼び出されます。 ClassCastExceptionは、その外部コードまたは配列を返すメソッドで警告なしに外部コードからスローされます。

public class Foo<E> {

    private E[] myArray = (E[])new Object[42];

    public E[] getArray() {
        return myArray;
    }

}

// some outside code:
Foo<String> foo = new Foo<String>();
String[] stringArray = foo.getArray(); // ClassCastException
3
user102008

もちろん、配列をObject []として宣言し、プライベートアクセサを次のように記述できます。

Object[] elements = ...;

@SuppressWarnings("unchecked")
private E getElement(int index)
{
    return (E)elements[index];
}

このように、あなたとあなたのコードの他のすべての読者にある宣言を持つフィールドがなく、キャストを単一の場所に制限します。コンパイラーが非具体化型に実際の実際のキャストを行う方法がないため、キャストは何もしません。

これは実際に、多くの適切に作成されたコレクション実装の内部で起こっていることです。

E []へのキャストは、実際の実際のコレクションにパフォーマンス上の利点をもたらす可能性があるため、他の多くのコードに影響を与えるコードを作成するいくつかの場所に行く方法です。

例外的なものは貴重なものになる可能性があるので、コメントを使用してください。フィールドのスコープを制限します。どのステップでも何をしているのかを3回考えます。大丈夫です:)

ただし、パフォーマンスが最重要でない場合は、アクセサを使用するだけです????

0
yeoman