Java Generics: создание массивов с параметризованными типами: незаконно? - PullRequest
2 голосов
/ 09 февраля 2012

Я должен быть смущен здесь.

Я везде читал, что в генериках массивы параметризованных типов недопустимы.

Пример из AngelikaLanger :

static void test() {  
  Pair<Integer,Integer>[] intPairArr = new Pair<Integer,Integer>[10] ; // error  
  addElements(intPairArr);   
  Pair<Integer,Integer> pair = intPairArr[1];  
  Integer i = pair.getFirst();  
  pair.setSecond(i);  
} 

Цитата из Лангера (но везде, где я читал, написано то же самое):

Компилятор запрещает создание массивов, чей тип компонента конкретный параметризованный тип, такой как пара в нашем пример. Мы обсуждали в предыдущей записи, почему это разумно что компилятор квалифицирует пару [] как недопустимую.

Пока все хорошо.

Но в моем коде здесь:

private MyEntry<E> [] elements = (MyEntry<E>[])new Object[capacity];  

Я делаю именно это, он прекрасно компилируется (я использую eclipse), но получаю ошибку исключения приведения класса (объект не может быть приведен к MyEntry):

Мой вопрос: почему эта строка компилируется в первую очередь?

Я думал, что это создание запрещено компилятором.

Что я здесь делаю неправильно / иначе?

ОБНОВЛЕНИЕ:

На той же странице, почему я могу успешно сделать:

List<E> elements[] = (List<E>[])new LinkedList[capacity];  

и не имеют никаких исключений времени выполнения ?

ОБНОВЛЕНИЕ:

Везде, где я читал (упоминал Лангера, поскольку она часто цитируется), говорится, что это объявление (массивы параметризованных типов) запрещено компилятором.
Я могу понять, что происходит после этого.
Я не могу понять, почему компилятор не сообщает об ошибке.
Я не осуждаю, я говорю везде, где читаю, там говорится, что это не компилируется.
Я что-то не так читаю?

UPDATE: Я видел некоторые комментарии, связанные с отсутствующим параметром в части new.
Это также имеет нет проблема:

List<Entry<KeyType, ValueType>> table[] = (List<Entry<KeyType, ValueType>>[])new LinkedList[capacity];

Ответы [ 3 ]

2 голосов
/ 09 февраля 2012

В вашем первом примере нет проблем с созданием экземпляров - вот что вы создаете:

new Object[capacity]

Совершенно законно.Тем не менее, вы получаете исключение времени выполнения при попытке приведения, потому что массив Object не является массивом MyEntry<E>.Возможно, у вас есть точка зрения, что cast или объявление может быть отклонено компилятором, если эти универсально параметризованные массивы не могут существовать, хотя это зависит от того, в каком порядке стирается порядок.в любом случае, сама реализация в порядке.

Во втором примере вы создаете неуниверсальный массив LinkedList.Затем вы присваиваете его обобщенной ссылке, которая во время выполнения будет удалена до List[].Это прекрасно работает (потому что, правильно или неправильно, массивы ковариантны).

Я не уверен, почему вы ожидали исключения во время выполнения;это не сильно отличается от вызова, скажем

List<E> = new LinkedList();

Вы бы получили некоторые неконтролируемые предупреждения, но ничего, что могло бы помешать компиляции или запуску кода.

1 голос
/ 10 февраля 2012

Вы совершенно не поняли того, что прочитали. Нет ничего плохого в том, чтобы иметь тип , который является массивом параметризованного типа: MyEntry<E>[] или HashMap<String,Integer>[][] или чем-то еще. Вы можете иметь все переменные таких типов, которые вам нужны, и использовать их везде, где можно использовать тип.

Однако, при создании массива вы не можете сделать что-то вроде new MyEntry<E>[...]. Это не разрешено языком (из соображений безопасности типов мы не будем здесь вдаваться), поэтому это ошибка компиляции.

Лучшее решение - либо new MyEntry[] (массив необработанного типа), либо new MyEntry<?>[] (массив подстановочного типа); любой из них разрешен языком. Оба из них потребуют от вас явного приведения обратно к MyEntry<E>[].

Поскольку вы спрашиваете о примерах кода, ваш первый пример синтаксически правильный (в new Object[...] нет ничего плохого, и синтаксически можно привести его к MyEntry<E>[]), поэтому нет ошибки компиляции. Однако проверка выполнения приведения не выполняется во время выполнения, поскольку фактический тип объекта Object[] не является подтипом MyEntry[].

Второй пример кода также синтаксически корректен, и плюс проверка выполнения приведения успешна (LinkedList[] - это подтип List[]).

1 голос
/ 09 февраля 2012

Потому что LinkedList является экземпляром List. Но Object является НЕ экземпляром MyEntry. Также компилятор не проверяет, может ли один объект быть приведен к другому или нет. Потому что это операция во время выполнения.

Вы должны использовать:

private MyEntry<E> [] elements = new MyEntry [capacity];

Или:

class SomeOtherEntry extends MyEntry {}

private MyEntry<E> [] elements = new SomeOtherEntry [capacity];

Но не:

class SomeOtherEntry extends MyEntry {}

private SomeOtherEntry <E> [] elements = new MyEntry [capacity];

UPDATE:

List<Entry<KeyType, ValueType>> [] table = (List<Entry<KeyType,ValueType>> []) new Linked[capacity];
...