Как получить параметризованный экземпляр класса

StackOverflow https://stackoverflow.com/questions/71585

  •  09-06-2019
  •  | 
  •  

Вопрос

Поскольку были введены дженерики, класс параметризован, так что List.class создает класс<List>.Это и так понятно.

Чего я не могу понять, так это как получить экземпляр класса типа, который сам параметризуется, т.е.Класс<List<String>>.Как в этом фрагменте:

public class GenTest {
    static <T> T instantiate(Class<T> clazz) throws Exception {
        return clazz.newInstance();
    }
    public static void main(String[] args) throws Exception {
        // Is there a way to avoid waring on the line below
        // without using  @SuppressWarnings("unchecked")?
        // ArrayList.class is Class<ArrayList>, but I would like to
        // pass in Class<ArrayList<String>>
        ArrayList<String> l = GenTest.instantiate(ArrayList.class);
    }
}

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

Это было полезно?

Решение

Класс class - это представление типа во время выполнения.Поскольку параметризованные типы подвергаются стиранию типа во время выполнения, объект class для Class будет таким же, как для Class<List<Integer>> и Class<List<String>>.

Причина, по которой вы не можете создать их экземпляр, используя обозначение .class, заключается в том, что это специальный синтаксис, используемый для литералов класса.Тот Самый Спецификация языка Java специально запрещает этот синтаксис при параметризации типа, вот почему List<String>.class не разрешен.

Другие советы

Классы представляют собой классы, загружаемые загрузчиком классов, которые являются необработанными типами.Чтобы представить параметризованный тип, используйте java.lang.reflect.ParameterizedType.

Я не думаю, что ты сможешь сделать то, что пытаешься.Во-первых, ваш метод instantiate не знает, что он имеет дело с параметризованным типом (вы могли бы так же легко передать его java.util.Date.class).Во-вторых, из-за стирания выполнение чего-либо особенно специфичного с параметризованными типами во время выполнения затруднено или невозможно.

Если бы вы подошли к проблеме по-другому, есть другие маленькие хитрости, которые вы можете сделать, например, вывод типа:

public class GenTest
{
    private static <E> List<E> createList()
    {
        return new ArrayList<E>();
    }

    public static void main(String[] args)
    {
        List<String> list = createList();
        List<Integer> list2 = createList();
    }
}

Единственное, что вы можете сделать, это создать экземпляр List<String> непосредственно и назовите ее getClass():

instantiate(new List<String>() { ... }.getClass());

Для типов с несколькими абстрактными методами, такими как List, это довольно неловко.Но, к сожалению, вызов конструкторов подкласса (например new ArrayList<String>) или заводские методы (Collections.<String>emptyList()) не работай.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top