Подтвердить что ты не робот

Работа с ArrayStoreException

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[]?

4b9b3361

Ответ 1

В Java массив также является объектом.

Вы можете поместить объект подтипа в переменную супертипа. Например, вы можете поместить объект String в переменную Object.

К сожалению, определение массива в Java как-то нарушено. String[] считается подтипом Object[], но это неправильно! Более подробное объяснение читается о "ковариации и контравариантности", но суть в этом: тип следует рассматривать как подтип другого типа, только если подтип выполняет все обязательства супертипа. Это означает, что если вы получаете объект подтипа вместо объекта супертипа, вы не должны ожидать, что поведение противоречит контракту супертипа.

Проблема в том, что String[] поддерживает только часть контракта Object[]. Например, вы можете читать значения Object из Object[]. И вы также можете читать значения Object (которые являются объектами String) из String[]. Все идет нормально. Проблема заключается в другой части контракта. Вы можете поместить любой Object в Object[]. Но вы не можете поставить Object в String[]. Поэтому String[] не следует рассматривать как подтип Object[], но спецификация Java говорит, что это так. И таким образом мы имеем такие последствия.

(Обратите внимание, что аналогичная ситуация появилась снова с общими классами, но на этот раз она была решена правильно. List<String> не является подтипом List<Object>, и если вы хотите иметь общий супертип для них, вам нужно List<?>, который доступен только для чтения, так как это должно быть также с массивами, но это не так. И из-за обратной совместимости, это слишком поздно, чтобы изменить его.)

В первом примере функция String.split создает объект String[]. Вы можете поместить его в переменную Object[], но объект остается String[]. Вот почему он отклоняет значение Integer. Вам нужно создать новый массив Objects[] и скопировать значения. Вы можете использовать функцию System.arraycopy для копирования данных, но вы не можете избежать создания нового массива.

Ответ 2

Нет, нет способа избежать копирования массива, возвращаемого split.

Массив, который возвращает split, на самом деле является String[], а Java позволяет назначить его переменной типа Object[]. Тем не менее, он по-прежнему является String[], поэтому, когда вы пытаетесь сохранить что-то еще, кроме String, вы получите ArrayStoreException.

Для получения дополнительной информации см. 4.10.3. Подтипирование между типами массивов в спецификации языка Java.

Ответ 3

Есть, конечно, другие варианты, например, вы реализуете свой собственный метод split, который возвращает массив Object напрямую. Я не уверен, хотя что на самом деле беспокоит вас с временным массивом String?

Кстати, вы можете сократить свой код несколькими строками, используя System.arrayCopy, вместо того чтобы реализовать собственный цикл для копирования элементов массива:

System.arrayCopy(s, 0, o, 0, s.length);

Ответ 4

Если вам не нужно использовать "split"... Тогда вы можете избежать копирования...