Синтаксис Java: Generics

Это работает, чтобы вернуть список ints:

public List<Integer> GetIListImpl() {
    return new ArrayList<Integer>();
}

Но что, если я хочу, чтобы вызывающий вызывал общий тип? Что-то вроде этого, хотя синтаксически я не уверен, как это сделать:

public List<T> GetIListImpl<T>() {
    return new ArrayList<T>();
}

Использование будет:

    List<String> = GetIListImpl<String>();

Ответы

Ответ 1

Об общих static factory методах параметризованных типов

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

Вы можете написать такие общие методы, как эти:

public static <T> List<T> newArrayList() {
    return new ArrayList<T>();
}
public static <K,V> Map<K,V> newHashMap() {
    return new HashMap<K,V>();
}

Тогда вы можете просто написать:

// absolutely type-safe!!! no compilation warnings at all!!!

List<String> names = newArrayList();

List<Integer> nums = newArrayList();

Map<String, List<String>> map = newHashMap();

Обратите внимание, что в некоторых контекстах вышеприведенные методы не должны быть static, и вы можете отказаться от имен реализации class из методов и использовать только имена interface (например, newList, newMap).


Подтверждение от Effective Java 2nd Edition

Этот тип универсального метода type-inferring static factory фактически одобрен Effective Java 2nd Edition; у него была уникальная привилегия быть первым пунктом, обсуждавшимся в книге.

Вот соответствующие цитаты из пункта 1: Рассмотрим методы static factory вместо конструкторов:

Четвертое преимущество методов static factory заключается в том, что они уменьшают многословность создания экземпляров с параметризованным типом.

При вызове конструктора параметризованного класса, к сожалению, вы должны указать параметры типа, даже если они очевидны из контекста. Это обычно требует, чтобы вы предоставляли параметры типа дважды в быстрой последовательности:

    Map<String,List<String>> m = 
        new HashMap<String,List<String>>();

Эта избыточная спецификация быстро становится болезненной по мере увеличения длины и сложности параметров типа. Однако с фабриками static компилятор может определить параметры типа для вас. Это называется выводом типа. Например, предположим, что HashMap предоставил этот static factory:

    public static <K,V> HashMap<K,V> newInstance() {
        return new HashMap<K,V>();
    }

Затем вы могли бы заменить словосочетание выше на эту краткую альтернативу:

    Map<String,List<String>> m = HashMap.newInstance();

К сожалению, стандартные версии коллекций, такие как HashMap, не имеют методов static factory начиная с версии 1.6, но вы можете поместить эти методы в свой собственный класс утилиты. Более того, вы можете предоставить такие фабрики static в своих параметризованных классах.

Элемент также предписывает общее соглашение об именах для этих методов static factory:

  • getInstance - возвращает экземпляр, который описывается параметрами [...]
  • newInstance - Как getInstance, за исключением того, что он гарантирует, что каждый возвращаемый экземпляр отличается от всех остальных.
  • new Type - Как newInstance, но используется, когда метод factory находится в другом классе. Type указывает тип объекта, возвращаемого методом factory.

В параметрах явного типа

В большинстве случаев вам не нужно явно указывать параметры типа, так как система вывода типов типов generic Java обычно может определить, что вам нужно.

Тем не менее, чтобы предоставить явные параметры типа, синтаксис заключается в том, чтобы поместить его перед именем метода (не после). Здесь приведен пример вызова с явным параметром общего метода <T> List<T> emptyList() из java.util.Collections:

Collections.<String>emptyList();
// Collections.emptyList<String>(); // DOES NOT COMPILE

Обратите внимание, что синтаксический притвор для явной тип параметризации для вызова общего метода заключается в том, что вы должны квалифицировать тип (if static) или объект, к которому вы вызываете метод, даже если их можно опустить, если он не была явной параметризацией.


Ссылки


Приложение: коллекция factory методов из Guava

Следует отметить, что Guava фактически уже предоставляет методы static factory для типов в Структура коллекций Java:

Из основного package com.google.common.collect:

Фактически, в духе рекомендации Эффективного Java 2nd Edition, собственные коллекции Guava не предоставляют конструкторы public, а вместо этого предоставляют методы static create() factory:

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

Ответ 2

Синтаксис будет

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

Ты был близок.

И это больше похоже на:

MyClass.<Integer>getIListImpl();

Ответ 3

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

class Test
{
    public static <T> List<T> getListImpl() {
        return new ArrayList<T>();
    }
}

Посмотрите на позицию аргумента Generic type, он стоит перед именем метода. Для классов он стоит за именем класса. Поэтому вместо того, чтобы добавлять общий тип после имени метода, вы вызываете его так:

List<Integer> l = Test.<Integer>getListImpl()

Вы должны вызвать его либо с именем класса, либо с экземпляром. Компилятор не любит следующее:

List<Integer> l = <Integer>getListImpl()

Иногда он работает без общего типа

List<Integer> l = getListImpl()

Здесь класс сравнения и общий метод

class Test<T>{}//Generic after class name
T<Integer> t = new T<Integer>();
void <T> methName(){}//Generic before method name
t.<Integer>methName();