Почему я не могу явно передать аргумент типа универсальному методу Java? - PullRequest
22 голосов
/ 24 августа 2008

Я определил функцию 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 от компилятора.

Ответы [ 4 ]

33 голосов
/ 25 августа 2008

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

Object list = Collections.<String> emptyList();
22 голосов
/ 24 августа 2008

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

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

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

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

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

.
,

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

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

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

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

0 голосов
/ 24 августа 2008

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

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

Редактировать: добавлена ​​ссылка. Повторное редактирование: обнаружена ошибка на SO:)


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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...