Страницы

Поиск по вопросам

суббота, 28 декабря 2019 г.

Generic и массивы

#java #generics


Доброго всем времени!
Думал, что я знаю, как использовать дженерики, а оказалось xто и нет. Код:
class MyClass {
   T mas[];

   void foo() {
       mas = new T[10]; // ошибка!
   }
}

Вопрос - почему возникает ошибка?    


Ответы

Ответ 1



Это ограничение реализации дженериков в Java. Дело в том, что дженерики — конструкция времени компиляции, информации о настоящем типе в рантайме нет. Это называется type erasure: Java заменяет везде T на Object в скомпилированном коде (если нет дальнейших условий). При создании массива, однако, Java нуждается в информации о типе элементов, но этот тип недоступен, дженерик не имеет возможности узнать тип своего параметра T! Поэтому и создать массив неизвестного (для дженерика) типа T в Java невозможно. В качестве рекламы корпорации мирового зла замечу, что дженерики в C# были разработаны с учётом опыта Java и избежали проблемы, с которой вы столкнулись. На Stackoverflow обсуждаются возможные workaround'ы. Самый простой — передавать T.class в конструкторе MyClass, и конструировать массив следующим образом: mas = (T[])Array.newInstance(TClass, 10);

Ответ 2



@nightin_gale, Еще один вариант так сказать "из жизни": вместо поля TClass объявить абстрактный метод в духе: protected Class getClassDef(); и, переопределяя его в дочерних классах: public class MyStringClass extends MyClass { protected Class getClassDef() { return String.class; } } пользоваться в родительском: mas = (T[])java.lang.reflect.Array.newInstance(getClassDef(), 10);

Ответ 3



А почему бы не сделать вот так: mas = (T[])(new Object[10]);

Ответ 4



Ваш случай попадает под одно из ограничений для дженериков - невозможно создать экземпляр массива или переменной параметризованного типа. Как было описано выше во время компиляции вся информация об использовании параметра типа удаляется и подставляется конкретный, указанный вами тип. Необходимо это для обратной совместимости кода. Поэтому и выходит, что Вы пытаетесь создать экземпляр неизвестного типа, что в принципе невозможно. Но можете передавать массив снаружи, при вызове метода. Мой ответ весьма упрощен, и является неполным, однако все же является одним из решений данной проблемы =) class MyClass { T mas[]; void foo(T arr[]) { mas = arr; } }

Комментариев нет:

Отправить комментарий