Подтвердить что ты не робот

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

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

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

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

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

Почему я не могу вызвать его, явно передав аргумент generic type?

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

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

4b9b3361

Ответ 1

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

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

Ответ 2

Вы можете, если вы передадите этот тип в качестве параметра метода.

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

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

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

Для действительно отличных часто задаваемых вопросов по Java-дженерикам см. часто задаваемые вопросы об генераторах Angelika Langer.

.
,

Последующий:

В этом контексте не имеет смысла использовать аргумент массива, как в 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 ] );
}

Ответ 3

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

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

Ответ 4

@pauldoo Да, вы совершенно правы. Это одна из слабых сторон с java generics 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>();
}

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