Инициализация Java-массива с типом
Следующий код меня смущает:
Object[] arr1 = new String[]{"a", "b", "c"};
Object[] arr2 = {"a", "b", "c"};
String[] a = (String[]) arr1; // ok
String[] b = (String[]) arr2; // ClassCastException
System.out.println(arr1.getClass().getName()); // [Ljava.lang.String;
System.out.println(arr2.getClass().getName()); // [Ljava.lang.Object;
Я пытаюсь понять, почему две инициализации отличаются друг от друга. Первый - это объявление, а второе - ярлык. Оба объявлены как Object[]
Мое наивное понимание таково:
Object[] arr2 = {"a", "b", "c"}; // is a syntax sugar of
Object[] arr2 = new Object[] {"a", "b", "c"};
Таким образом, тип времени выполнения arr2
равен Object[]
, который не может быть преобразован в String[]
.
Но здесь все странно, потому что Java Array является ковариантным:
String[]
является подклассом Object[]
, а arr2
является точно a String[]
, отключение от Object[]
до String[]
на arr2
должно работать.
Любое объяснение этому высоко ценится.
Ответы
Ответ 1
Поскольку arr2
является Object[]
, вам ничего не мешает писать
arr2[0] = new Object();
прямо перед вашим актом, случай, когда актер больше не будет иметь никакого смысла.
Из-за того, как работает синтаксис инициализатора, обратите внимание также на следующее:
Object x = {"a", "b"}; // error: illegal initializer for Object
Object[] a = {"a", "b"}; //a has class [Ljava.lang.Object;
String[] b = {"a", "b"}; //b has class [Ljava.lang.String;
Компилятор определяет, хотите ли вы, чтобы ваш массив был Object[]
или String[]
на основе вашего объявления.
Ответ 2
arr2 - это точно строка []
Нет, это не так: Object[]
, как вы сказали, ваша строка эквивалентна:
Object[] arr2 = new Object[] {"a", "b", "c"};
Это a Object[]
, который имеет элементы, которые в настоящий момент являются ссылками на строки... но вы также можете написать:
arr2[0] = new Object(); // Fine, because arr2 is an Object[]
Если вы сделали то же самое с arr1
, вы получите исключение:
arr1[0] = new Object(); // Fine at compile time, will throw an exception
Конечно, вы можете проверить фактический тип времени выполнения объекта с помощью getClass
:
System.out.println(arr2.getClass());
Ответ 3
Почти правильно. Ваша логика здесь испорчена:
arr2 is exactly a String[]
Нет, это не так. Это массив объектов. Тот факт, что вы только что добавили Strings в этот массив, не имеет смысла. Вы могли написать
arr2 = {"a", new Integer(5) };
тоже.
Вероятно, это делает его более понятным, почему вам не разрешено использовать такой массив для String [].
Ответ 4
Object[] arr2 = {"a", "b", "c"};
В этом случае объявленный массив равен
Object[] arr2 = new Object[] {"a", "b", "c"};
Итак, элементы в arr2 могут быть любыми типами Object
. И на линии
String[] b = (String[]) arr2; // ClassCastException
Потому что вы пытаетесь сделать целое Object[]
на String[]
.
Где, как в первом, вы явно указываете, что все объекты являются строками
Object[] arr1 = new String[]{"a", "b", "c"};