2012-02-09 4 views
2

Я должен быть здесь смущен.Java Generics: Массирование массивов с параметризованными типами: незаконно?

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

Пример из 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]; 

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

Вопрос в том, почему эта линия компилируется в первую очередь?

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

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

UPDATE:

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

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

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

UPDATE:

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

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

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

'LinkedList' реализует' List', так что ** downcast ** является приемлемым; 'Object' не является подклассом' MyEntry', так что ** upcast ** вызывает ошибку. – Viruzzo

+0

Пожалуйста, прочитайте обновленный OP – Cratylus

+0

Вы делаете 'новый LinkedList []': там есть параметр ** no ** type, поэтому проблем нет; что вы не можете сделать, это 'new LinkedList []'. Выполнение типизированного приведения не имеет ничего общего с тем, что вы не можете выполнить инициализацию и из-за типа erasure '(List [])' во время выполнения становится '(List [])', действительным списком для 'new LinkedList [] '. – Viruzzo

ответ

1

Поскольку LinkedList является экземпляром List. Но Object является NOT экземпляр 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]; 
2

В первом примере, нет никаких проблем с конкретизацией - вот именно то, что вы создаете:

new Object[capacity] 

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

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

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

List<E> = new LinkedList(); 

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

+0

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

+0

Моя точка зрения заключалась в том, что нигде вы не создаете общие массивы * - вы создаете не-общие массивы, а затем пытаетесь отбросить их на что-то, что может или не может получиться. Если ваш первый пример был «private MyEntry [] elements = new MyEntry [capacity];' он не смог бы скомпилировать с ошибкой «создание общего массива» - надеюсь, вы можете понять, почему это отличается от того, что вы * на самом деле * иметь. –

+0

С другой стороны, если вы изменили строку на «MyEntry [] elements = new MyEntry [capacity];», то создание массива будет работать (так как теперь оно не является общим), * и * приведение должно работать, поэтому это будет действовать примерно так, как вы могли бы ожидать. Возвращаясь к цитате Лангера, важная часть состоит в том, что она упоминает создание массивов, тип компонента которых представляет собой конкретный параметризованный тип **. 'Object' не параметризуется, а' MyEntry' является сырым типом, поэтому оба они работают. 'MyEntry ' - конкретный параметризованный тип, поэтому создание массива с этим не удастся. –

1

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

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

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

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

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

+0

Как насчет третьего примера? Также ваш второй пара «Тем не менее, с созданием массива, ....» с анализом моих примеров кода представляется мне непоследовательным. Я ничего не понимаю, я думаю .... – Cratylus

+0

@ user384706: третий пример также прекрасен. Единственное отличие между вторым и третьим примерами - это тип броска. Типы в обоих случаях действительны. Я не понимаю, что вы пытаетесь продемонстрировать – newacct

+0

@ user384706: что вы не можете рассказать о моем анализе? – newacct

Смежные вопросы