Сведения о вопросе

PIRLO

04:41, 18th August, 2020

Теги

java   generics   syntax    

Почему я не могу явно передать аргумент типа в универсальный метод Java?

Просмотров: 383   Ответов: 4

Я определил функцию Java:

static <T> List<T> createEmptyList() {
    return new ArrayList<T>();
}

Один из способов назвать это так:

List<Integer> myList = createEmptyList(); // Compiles

Почему я не могу вызвать его, явно передавая аргумент универсального типа? :

Object myObject = createEmtpyList<Integer>(); // Doesn't compile. Why?

Я получаю ошибку Illegal start of expression от компилятора.



  Сведения об ответе

padenie

13:14, 1st August, 2020

Если компилятор java не может самостоятельно определить тип параметра для статического метода, вы всегда можете передать его, используя полное имя метода: Class . < тип > method();

Object list = Collections.<String> emptyList();


  Сведения об ответе

crush

11:36, 10th August, 2020

Можно, если передать тип в качестве параметра метода.

static <T> List<T> createEmptyList( Class<T> type ) {
  return new ArrayList<T>();
}

@Test
public void createStringList() {
  List<String> stringList = createEmptyList( String.class );
}

Методы не могут быть обобщены таким же образом, как и тип, поэтому единственный вариант для метода с динамически типизированным универсальным типом возвращаемого значения-фу, это полный рот : -) - передать тип в качестве аргумента.

Для действительно отличного FAQ по Java дженерикам смотрите дженерики Анжелики Лангер FAQ . . .


Следовать за:

В этом контексте не имеет смысла использовать аргумент array, как в Collection.toArray( T[] ) . Единственная причина, по которой массив используется там, заключается в том, что один и тот же (предварительно выделенный) массив используется для хранения результатов (если массив достаточно велик, чтобы вместить их все). Это экономит на выделении нового массива во время выполнения все время.

Однако для целей обучения, если вы действительно хотите использовать типирование массива, синтаксис очень похож:

static <T> List<T> createEmptyList( T[] array ) {
  return new ArrayList<T>();
}

@Test
public void testThing() {
  List<Integer> integerList = createEmptyList( new Integer[ 1 ] );
}


  Сведения об ответе

lool

16:32, 20th August, 2020

Прошло уже довольно много времени с тех пор, как я копался в этих краях Java, но ... ..

Почему вы не можете сделать это, вероятно, был выбор дизайна разработчиками языка. Тем не менее, из-за стирания типа , используемого Java, универсальная информация все равно удаляется во время компиляции, поэтому в вашем примере она будет создавать точно такой же байтовый код, независимо от того, есть ли у вас параметр типа или нет.


  Сведения об ответе

LIZA

13:17, 11th August, 2020

@pauldoo Да, вы совершенно правы. Это одна из слабых сторон с java дженериками imho.

В ответ на Cheekysoft я хотел бы предложить также посмотреть, как это делается самими Java людьми, например T[] AbstractCollection#toArray (T[] a). Я думаю, что версия Cheekysofts лучше, но у Java есть преимущество в знакомстве.

Редактирования: добавил ссылку. Re-edit: нашел ошибку на SO :)


Последующие действия на Cheekysoft: Ну, так как это список какого-то типа, который должен быть возвращен, то соответствующий пример должен выглядеть примерно так:

static <T> List<T> createEmptyList( List<T> a ) {
  return new ArrayList<T>();
}

Но да, передача объекта класса явно лучше. Мой единственный аргумент - это знакомство, и в этом конкретном случае оно не стоит многого (на самом деле это плохо).


Ответить на вопрос

Чтобы ответить на вопрос вам нужно войти в систему или зарегистрироваться