import java.lang.reflect.Array;
public class PrimitiveArrayGeneric {
static <T> T[] genericArrayNewInstance(Class<T> componentType) {
return (T[]) Array.newInstance(componentType, 0);
}
public static void main(String args[]) {
int[] intArray;
Integer[] integerArray;
intArray = (int[]) Array.newInstance(int.class, 0);
// Okay!
integerArray = genericArrayNewInstance(Integer.class);
// Okay!
intArray = genericArrayNewInstance(int.class);
// Compile time error:
// cannot convert from Integer[] to int[]
integerArray = genericArrayNewInstance(int.class);
// Run time error:
// ClassCastException: [I cannot be cast to [Ljava.lang.Object;
}
}
Я пытаюсь полностью понять, как дженерики работают в Java. В третьем назначении в приведенном выше фрагменте для меня все немного странно: компилятор жалуется, что Integer[]
нельзя преобразовать в int[]
. Конечно, это утверждение на 100% верно, но мне интересно, ПОЧЕМУ компилятор подает эту жалобу.
Если вы прокомментируете эту строку и последуете «предложению» компилятора, как в 4-м назначении, компилятор фактически удовлетворен !!! СЕЙЧАС код компилируется просто отлично! Конечно, это безумие, поскольку, как предполагает поведение во время выполнения, int[]
не может быть преобразовано в Object[]
(то, во что T[]
стирается тип во время выполнения).
Итак, мой вопрос: почему компилятор "предлагает" назначить Integer[]
вместо 3-го назначения? Как компилятор может прийти к такому (ошибочному!) Заключению?
Пока что в этих двух ответах много путаницы, поэтому я создал еще один сбивающий с толку пример, чтобы проиллюстрировать основную проблему здесь:
public class PrimitiveClassGeneric {
static <T extends Number> T test(Class<T> c) {
System.out.println(c.getName() + " extends " + c.getSuperclass());
return (T) null;
}
public static void main(String args[]) {
test(Integer.class);
// "java.lang.Integer extends class java.lang.Number"
test(int.class);
// "int extends null"
}
}
Я единственный, кто считает абсолютно безумным, что компилятор позволяет компилировать приведенный выше код?
Было бы неразумно печатать, например, c.getSuperclass().getName()
в приведенном выше коде, так как я указал T extends Number
. Конечно, теперь getName()
будет выбрасывать NullPointerException
, когда c == int.class
, так как c.getSuperclass() == null
.
И для меня это очень веская причина отказаться от компиляции кода.
Возможно, окончательное сумасшествие:
int.class.cast(null);
Этот код компилируется И работает нормально.