Почему следующее условие возвращает true
с JDK 8, тогда как оно возвращает false
с JDK 9?
String[].class == Arrays.asList("a", "b").toArray().getClass()
Почему следующее условие возвращает true
с JDK 8, тогда как оно возвращает false
с JDK 9?
String[].class == Arrays.asList("a", "b").toArray().getClass()
Тип 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]);
Я бы сказал, что это была ошибка в JDK 8, и до этого она была исправлена.
List<T>.toArray()
всегда объявлялся как возвращающий Object[]
(см. JavaDoc) - что в действительности он возвращал String[]
в особом случае, было ошибкой.
Здесь есть несколько причин
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