#java #types #variadic-functions
#java #типы #переменные-функции
Вопрос:
Я наткнулся на этот раздел прокомментированного кода в StackOverflow. Это вызовет исключение во время выполнения. Вторая часть (раздел без комментариев) будет работать. Я не могу найти разницу между ними, поскольку оба метода возвращают массивы объектов. Возможно, мне не хватает некоторого базового понимания. Не могли бы вы мне помочь?
public class Safevarargs {
/*
static <Object> Object[] asArray(Object... args) {
return args;
}
static <Object> Object[] arrayOfTwo( Object a, Object b) {
return asArray(a, b);
}
public static void main(String[] args) {
String[] bar = arrayOfTwo("hi", "mom");
}
*/
static <Object> Object[] display(Object... args) {
return args;
}
public static void main(String[] args) {
String[] str = display("hi", "mom");
System.out.print(str[0]);
}
}
Комментарии:
1. Что является исключением?
2. Крайне плохой практикой является использование имени, подобного
Object
для переменной универсального типа.3. У вас есть какое-то ненужное повторение. Нет никакого способа
asArray
ошибочным, но нетdisplay
.
Ответ №1:
Я полагаю, что у вас возникли проблемы с приведением. Когда вы используете часть
static <Object> Object[] display(Object... args)
на самом деле компилятор видит
static <Object> Object[] display(Object[]... args)
затем он дополнительно преобразует его в это
static <Object> Object[] display(List[]... args)
Это может допускать значения, которых там быть не должно
допустим, вы создаете массив объектов из строки и пытаетесь добавить к нему int. Это может вызвать проблемы с различными типами. Возможно, вы захотите переработать его без использования универсального объекта.
В качестве альтернативы вы могли бы использовать тег @SafeVarargs .
Комментарии:
1. Компилятор видит
Object[]
при просмотреObject...
и ни в коем случаеList
не задействован.
Ответ №2:
Чтобы объяснить эту проблему, нам просто нужно знать, как работает generic в java. компилятор использует информацию об общем типе внутри в процессе компиляции, генерируя ошибки, связанные с типом, при обработке исходных текстов. Затем, после завершения проверки, компилятор генерирует байтовый код со стертым типом, при этом все ссылки на общие типы заменяются соответствующим стиранием типа.
в вашем втором примере он компилируется в строку во время компиляции. но в вашем первом примере, поскольку asArray вызывается другим универсальным методом, он будет скомпилирован в объект во время компиляции. В результате во время выполнения объект [] не может быть преобразован в String[], что вызовет исключение приведения класса. надеюсь, это может вам помочь
Ответ №3:
Здесь интересная ситуация. В первом случае Java жалуется на преобразование из массива объектов в массив строк.
java.lang.ClassCastException: [Ljava.lang.Объект; не может быть приведен к [Ljava.lang.Строка;
Во втором случае он справляется с этим просто отлично. Проблема, похоже, заключается в стирании типа. При asArray
возврате он возвращает массив, типизированный на основе его параметров. Эта информация стирается в контексте arrayOfTwo
, где тип просто становится Object[]
, и тот факт, что содержимое является строками, больше не доступен.
Взгляните на этот пост об удалении типов и невоспроизводимых типах, а также о последствиях для переменных. Он предоставляет некоторый контекст для предупреждения, которое генерирует код, о «возможном загрязнении кучи»:
Safevarargs.java:11: предупреждение: [снято] Возможное загрязнение кучи от параметризованного объекта типа vararg
статический объект[] отображение (объект… аргументы) {
^ где объект — переменная типа:
объект расширяет java.lang.Объект, объявленный в методе display(Object …)
Из документации:
Загрязнение кучи происходит, когда переменная параметризованного типа ссылается на объект, который не относится к этому параметризованному типу.