これは、何ヶ月も前に Java 開発者が行った取引の結果です。奇妙に思えるかもしれませんが、この機能はArrays.sort
( で呼び出されることもあります) などの多くのメソッドにとって重要ですCollections.sort
。基本的に、Object[] をパラメーターとして受け取るメソッドは、X[] (X は Object のサブクラス) がサブタイプと見なされない場合、意図したとおりに実行されなくなります。たとえば、配列が特定の状況下で読み取り専用になるように作り直された可能性はありますが、その場合、問題は「いつ?」になります。
一方では、引数としてメソッドに渡された配列を読み取り専用にすると、コーダーがその場で変更を行う能力が妨げられる可能性があります。一方、配列が引数として渡される場合に例外を作成しても、コーダーは、整数配列が呼び出し元によって渡されたものである場合に文字列を格納するなど、不正な変更を行うことができます。
しかし、「(たとえば) Integer[] は Object[] のサブタイプではない」と言う結果は、Object[] と Integer[] に対して別のメソッドを作成しなければならない危機です。このようなロジックの拡張により、String[]、Comparable[] などに対して個別のメソッドを作成する必要があるとさらに言えます。すべてのタイプの配列には、それらのメソッドがまったく同じであったとしても、個別のメソッドが必要になります。
これはまさに、ポリモーフィズムが存在する状況です。
ただし、ここでポリモーフィズムを許可すると、残念ながら、配列に値を不正に格納しようとする試みが許可され、ArrayStoreException
そのようなインスタンスが発生した場合は がスローされます。ただし、これは支払うべき小さな代償であり、ArrayIndexOutOfBoundsException
.
ArrayStoreException
ほとんどの場合、2 つの方法で簡単に防ぐことができます (ただし、他の人の行動を制御することはできません)。
1) 実際のコンポーネント
の型を知らずにオブジェクトを配列に格納しようとしないでください。操作している配列がメソッドに渡されたとき、それがどこから来ているかは必ずしもわからないため、コンポーネント タイプのクラスが final (つまり、サブクラスがない) でない限り、安全であると想定することはできません。
上記の質問のように、配列がメソッドから返される場合は、メソッドを理解してください。実際の型が戻り型のサブクラスである可能性はありますか? その場合、これを考慮に入れる必要があります。
2)
ローカルで動作する配列を最初に初期化するときは、フォームX[] blah = new X[...];
orX[] blah = {...};
または (Java 10 以降) を使用しvar blah = new X[...];
ます。次に、この配列に X 以外の値を格納しようとすると、コンパイラ エラーが発生します。XはY[] blah = new X[...];
Y のサブクラスです。
上記の問題のように、間違ったタイプのコンポーネントを格納したい配列がある場合、他の人が示唆しているように、適切なタイプの新しい配列を作成し、情報をコピーする必要があります...
Object[] o = Arrays.copyOf(s, s.length, Object[].class); //someone demonstrate System.arrayCopy. I figure I show another way to skin cat. :p
o[0] = 42;
または、格納するコンポーネントを何らかの方法で適切な型に変換する必要があります。
s[0] = String.valueOf(42);
42 != "42" であるため、どのパスを使用するかを決定する際には、コードの残りの部分にどのように影響するかを考慮する必要があります。
ジェネリックに関するメモで終わりたいと思います(以前の回答で対処したように)。ジェネリクスは実際、無防備なコーダーを驚かせることができます。次のコード スニペットを検討してください (ここから変更)。
import java.util.List;
import java.util.ArrayList;
public class UhOh {
public static void main(String[] args) {
List<Integer> list = new ArrayList<Integer>();
WildcardFixed.foo(list);
list.add(6);
System.out.println(list); // ¯\_(ツ)_/¯ oh well.
int i = list.get(0); //if we're going to discuss breaches of contract... :p
}
}
class WildcardFixed /*not anymore ;) */ {
static void foo(List<?> i) {
fooHelper(i);
}
private static <T> void fooHelper(List<T> l) {
l.add((T)Double.valueOf(2.5));
}
}
ジェネリック、紳士淑女。:p