Почему Arrays.asList(...). ToArray(). GetClass() дает разные результаты в JDK 1.8 и 11?

Почему следующее условие возвращает true с JDK 8, тогда как оно возвращает false с JDK 9?

String[].class == Arrays.asList("a", "b").toArray().getClass()

Ответ 1

Тип List возвращаемый asList - Arrays$ArrayList. Метод toArray в JDK 8 для этого класса:

@Override
public Object[] toArray() {
    return a.clone();
}

Но в JDK 9+ это:

@Override
public Object[] toArray() {
    return Arrays.copyOf(a, a.length, Object[].class);
}

В обоих случаях String[] передается asList, но в случае JDK 8 он клонируется, который сохраняет свой тип массива (String[]), а в JDK 9+ он копируется с использованием Arrays.copyOf с явным новым тип массива Object[].

Эта разница означает, что в JDK 8 Arrays.asList("a", "b").toArray().getClass() возвращает String[] а в JDK 9+ возвращает Object[], поэтому в JDK 9+ ваш выражение будет оцениваться как false.

Причиной этого изменения является JDK-6260652 с мотивировкой:

В документации Коллекции утверждается, что

collection.toArray()

"идентичен по функции"

collection.toArray(new Object[0]);

Однако реализация Arrays.asList не следует этому: если он создан с массивом подтипа (например, String[]), его toArray() вернет массив того же типа (потому что он использует clone()) вместо Object[].

Если позже кто-то попытается сохранить не-Strings (или что-то еще) в этом массиве, ArrayStoreException.

Так что это изменение было сделано, чтобы исправить предыдущее поведение.


Если это проблема для вас, в соответствующей заметке о выпуске предлагается это в качестве обходного пути:

Если эта проблема возникает, перепишите код для использования формы с одним аргументом toArray(T[]) и предоставьте экземпляр нужного типа массива. Это также устранит необходимость в приведении.

String[] array = list.toArray(new String[0]);

Ответ 2

Я бы сказал, что это была ошибка в JDK 8, и до этого она была исправлена.

List<T>.toArray() всегда объявлялся как возвращающий Object[] (см. JavaDoc) - что в действительности он возвращал String[] в особом случае, было ошибкой.

Ответ 3

Здесь есть несколько причин

1) Это ошибка в JDK 8, где должен возвращаться java.lang.Object но это не так, и это исправлено в JDK 9+

@Override
public Object[] toArray() {
    return a.clone();
}

2) оператор == всегда используется для сравнения ссылок, поэтому java.lang.String или java.lang.Object являются объектами, которые являются одноэлементными и неизменяемыми, загружаемыми во время запуска JVM.

System.out.println(String[].class.hashCode()); //2018699554
System.out.println(Arrays.asList("a", "b").toArray().getClass().hashCode()); //2018699554