Что является причиной, почему Java не позволяет нам делать
private T[] elements = new T[initialCapacity];
Я мог понять, что.NET не позволила нам делать это, как в.NET у Вас есть типы значения, которые во времени выполнения могут иметь различные размеры, но в Java все виды T будут ссылками на объект, таким образом имея тот же размер (исправьте меня, если я неправ).
Какова причина?
Это потому, что массивы Java (в отличие от дженериков) содержат во время выполнения информацию о типе своего компонента. Таким образом, вы должны знать тип компонента при создании массива. Поскольку вы не знаете, что такое T
во время выполнения, вы не можете создать массив.
Причина, по которой это невозможно, заключается в том, что Java реализует свои Generics исключительно на уровне компилятора, и для каждого класса создается только один файл класса. Это называется Type Erasure.
Во время выполнения скомпилированный класс должен обрабатывать все свои использования с помощью одного и того же байткода. Так, new T[capacity]
будет совершенно не знать, какой тип нужно инстанцировать.
Мне нравится косвенный ответ Автор Gafter . Однако я считаю, что это неправильно. Я немного изменил код Гафтера. Он компилируется и какое-то время работает, а затем взрывается там, где предсказал Гафтер.
class Box<T> {
final T x;
Box(T x) {
this.x = x;
}
}
class Loophole {
public static <T> T[] array(final T... values) {
return (values);
}
public static void main(String[] args) {
Box<String> a = new Box("Hello");
Box<String> b = new Box("World");
Box<String> c = new Box("!!!!!!!!!!!");
Box<String>[] bsa = array(a, b, c);
System.out.println("I created an array of generics.");
Object[] oa = bsa;
oa[0] = new Box<Integer>(3);
System.out.println("error not caught by array store check");
try {
String s = bsa[0].x;
} catch (ClassCastException cause) {
System.out.println("BOOM!");
cause.printStackTrace();
}
}
}
Результат -
I created an array of generics.
error not caught by array store check
BOOM!
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
at Loophole.main(Box.java:26)
Так что мне кажется, что вы можете создавать универсальные типы массивов в java. Я неправильно понял вопрос?
Цитата:
Массивы универсальных типов не разрешены, потому что они не звучат. В проблема связана с взаимодействием Массивы Java, которые не статически звук, но проверяется динамически, с дженериками, которые статически звук и не проверяется динамически. Вот как можно использовать лазейка:
class Box
{ конечный T x; Box (T x) { this.x = x; } } class Loophole { public static void main (String [] args) { Поле [] bsa = новое поле [3]; Объект [] oa = bsa; oa [0] = новое поле <Целое число> (3); // ошибка не обнаружена проверкой хранилища массива Строка s = bsa [0] .x; // БУМ! } } Мы предложили решить эту проблему проблема с использованием статически безопасных массивов (aka Variance), но, который был отклонен для Тигра.
- gafter
(я полагаю, что это Нил Гафтер , но не уверен)
См. Контекст здесь: http: //forums.sun .com / thread.jspa? threadID = 457033 & forumID = 316
Не предоставив достойного решения, вы просто получите что-то хуже, ИМХО.
Обычно это решается следующим образом.
T[] ts = new T[n];
заменяется на (при условии, что T расширяет Object, а не другой класс)
T[] ts = (T[]) new Object[n];
Я предпочитаю первый пример, однако более академические типы, похоже, предпочитают второй, или просто предпочитают не думать об этом.
Большинство примеров того, почему нельзя просто использовать Object[], в равной степени относятся к List или Collection (которые поддерживаются), поэтому я считаю их очень слабыми аргументами.
Примечание: это одна из причин, по которой сама библиотека Collections не компилируется без предупреждений. Если этот сценарий использования не может быть поддержан без предупреждений, то в модели generics что-то фундаментально нарушено IMHO.
Основная причина заключается в том, что массивы в Java являются ковариантными.
Есть хороший обзор здесь.