Почему я не могу явно передать аргумент типа универсальному методу Java?
Вопрос
Я определил функцию 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
из компилятора.
Решение
Если компилятор Java не может самостоятельно определить тип параметра для статического метода, вы всегда можете передать его, используя полное имя метода:Сорт .<Тип> метод();
Object list = Collections.<String> emptyList();
Другие советы
Вы можете, если передать тип в качестве параметра метода.
static <T> List<T> createEmptyList( Class<T> type ) {
return new ArrayList<T>();
}
@Test
public void createStringList() {
List<String> stringList = createEmptyList( String.class );
}
Методы не могут быть обобщены таким же образом, как тип, поэтому единственный вариант для метода с динамически типизированным универсальным типом возвращаемого значения — уф, это слишком громко :-) — это передать тип в качестве аргумента.
Если вам нужен действительно отличный FAQ по дженерикам Java, см. часто задаваемые вопросы по дженерикам Анжелики Лангер..
.
.
Следовать за:
В этом контексте не имеет смысла использовать аргумент массива, как в 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 ] );
}
Прошло довольно много времени с тех пор, как я копался в этих частях Java, но...
Почему вы не можете этого сделать, вероятно, это дизайнерский выбор разработчиков языка.Тем не менее, из-за стирание типа используется в Java, информация об обобщениях в любом случае удаляется во время компиляции, поэтому в вашем примере будет создан точно такой же байт-код, независимо от того, есть ли у вас параметр типа или нет.
@pauldoo Да, ты вполне прав.По моему мнению, это одна из слабых сторон Java-дженериков.
В ответ на Cheekysoft я хотел бы предложить также посмотреть, как это делают сами Java-разработчики, такие как T[] AbstractCollection#toArray(Т[]а).Я думаю, что версия Cheekysofts лучше, но у версии Java есть преимущество знакомости.
Редактировать:Добавлена ссылка.Повторное редактирование:Нашел ошибку в SO :)
Продолжение Cheekysoft:Ну, поскольку это список некоторого типа, который должен быть возвращен, соответствующий пример должен выглядеть примерно так:
static <T> List<T> createEmptyList( List<T> a ) {
return new ArrayList<T>();
}
Но да, передача объекта класса явно лучше.Мой единственный аргумент — это знакомство, и в данном случае оно ничего не стоит (на самом деле это плохо).