Могу ли я вызвать класс .class на общий тип в Java?

Мне было интересно, есть ли способ в Java сделать что-то вроде

Class c = List<String>.class;
Class c2 = List<Date>.class;

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

Map<Class, Object> dataMap = new HashMap<Class, Object>();
dataMap.put(c, listOfStrings);
dataMap.put(c2, listOfDates);

Не возможно ли это из-за стирания стилей во время выполнения?

Ответ 1

Вы не можете этого сделать, но вы можете достичь своей общей цели, используя тот же подход, что и Guice с TypeLiteral, Если вы уже используете Guice, я предлагаю вам использовать это напрямую - в противном случае вы можете создать свой собственный подобный класс.

По сути, идея заключается в том, что подклассы родового типа, которые задают аргументы типа, непосредственно сохраняют эту информацию. Итак, вы пишете что-то вроде:

TypeLiteral literal = new TypeLiteral<List<String>>() {};

Затем вы можете использовать literal.getClass().getGenericSuperclass() и получить от него аргументы типа. TypeLiteral сам не нужно иметь какой-либо интересный код (я не знаю, есть ли у него что-нибудь в Guice, по другим причинам).

Ответ 2

Нет, это невозможно. Вы даже не можете ссылаться на List<String>.class в своем коде - это приводит к ошибке компиляции. Для List существует только один объект класса, и он называется List.class.

Не возможно ли это из-за стирания стилей во время выполнения?

Правильно.

Btw это общий тип, а не аннотированный тип.

Update

С другой стороны, у вас может быть что-то довольно близкое к вашей карте выше, путем настройки Josh Bloch типичного гетерогенного контейнера (опубликованного в Effective Java 2nd Ed., Item 29) немного:

public class Lists {
    private Map<Class<?>, List<?>> lists =
            new HashMap<Class<?>, List<?>>();

    public <T> void putList(Class<T> type, List<T> list) {
        if (type == null)
            throw new NullPointerException("Type is null");
        lists.put(type, list);
    }

    public <T> List<T> getList(Class<T> type) {
        return (List<T>)lists.get(type);
    }
}

Приведение в getList не проверяется, предупреждая, но я боюсь, что мы не можем этого избежать. Однако мы знаем, что значение, хранящееся для класса X, должно быть List<X>, поскольку это гарантируется компилятором. Поэтому я считаю, что бросок безопасен (если вы играете по правилам, т.е. Никогда не вызываете putList с простым неопределенным параметром Class), поэтому его можно подавить с помощью @SuppressWarnings("unchecked").

И вы можете использовать его следующим образом:

Lists lists = new Lists();
List<Integer> integerList = new ArrayList<Integer>();
List<String> stringList = new ArrayList<String>();
...

lists.putList(Integer.class, integerList);
lists.putList(String.class, stringList);
List<Integer> storedList = lists.getList(Integer.class);

assertTrue(storedList == integerList);

Ответ 3

Это невозможно, поскольку вы пытаетесь.
Но вы можете украсить эти списки и создать вместо MyListDates и MyListString и сохранить их в hashmap