1. ホーム
  2. java

[解決済み] ArrayStoreExceptionへの対応

2022-02-10 23:22:33

質問

Object[] o = "a;b;c".split(";");
o[0] = 42;

スロー

java.lang.ArrayStoreException: java.lang.Integer

の間に

String[] s = "a;b;c".split(";");
Object[] o = new Object[s.length];
for (int i = 0; i < s.length; i++) {
    o[i] = s[i];
}
o[0] = 42;

はしない。

その例外に対処するために、一時的な String[] の配列は?

どのように解決するのですか?

Javaでは、配列は オブジェクト .

のオブジェクトを置くことができます。 サブタイプ の変数に入れることができます。 スーパータイプ . 例えば String オブジェクトを Object という変数があります。

残念ながら、Javaでの配列の定義は、何らかの形で壊れています。 String[] のサブタイプとみなされます。 Object[] が、それは いけない ! より詳しい説明は、quot;共分散と共分散" を読んでいただきたいのですが、要するに、こういうことです。ある型が他の型のサブ型とみなされるのは、そのサブ型が以下の条件を満たす場合だけです。 すべての義務 のスーパータイプです。つまり、スーパータイプオブジェクトの代わりにサブタイプオブジェクトを取得した場合、スーパータイプの契約に矛盾する動作を期待してはいけないということです。

問題は String[] をサポートするだけです。 部分 Object[] を契約することができます。例えば、次のようなことができます。 読む Object からの値 Object[] . また 読む Object の値(これはたまたま String オブジェクト)から String[] . ここまでは良いのですが 問題はコントラクトの他の部分です。あなたは 任意の ObjectObject[] . しかし 任意の ObjectString[] . したがって String[] のサブタイプと見なすべきではない。 Object[] しかし、Javaの仕様ではそうなっています。そのため、このような結果になってしまうのです。

(なお、ジェネリッククラスでも同様の事態が再び発生しましたが、今回は解決済みです 正しく . List<String> ではない のサブタイプである List<Object> ;そして、これらに共通のスーパータイプが必要な場合は List<?> これは読み取り専用です。配列の場合もそうであるべきですが、そうではありません。そして、後方互換性のために、それを変更するには遅すぎるのです)。

最初の例では String.split 関数は String[] オブジェクトを作成します。これを Object[] 変数に格納されますが、オブジェクトは String[] . このため Integer の値を指定します。を新たに作成する必要があります。 Objects[] の配列を作成し、その値をコピーします。を使うことができます。 System.arraycopy 関数を使用してデータをコピーすることもできますが、新しい配列を作成することを避けることはできません。