#java #generics
#java #общие сведения
Вопрос:
У меня есть класс, определенный следующим образом:
public class GenericClass<T> {
private final Class<T> type;
public GenericClass(Class<T> type) {
this.type = type;
}
public Class<T> getMyType() {
return this.type;
}
}
С помощью этого кода класса легко создать новый экземпляр класса с не-универсальным типом. Например:
GenericClass<String> c = new GenericClass<String>(String.class)
Мой вопрос заключается в следующем. Как я могу создать новый экземпляр класса с универсальным типом? Пример:
GenericClass<List<String>> c = new GenericClass<List<String>>(...)
Если я помещаю List<String>.class
, компилятор выдает мне ошибку. Какой синтаксис я должен использовать во время компиляции, чтобы указать конструктору правильный класс универсального типа?
Комментарии:
1. вам нужно сделать List.class,
2. Из-за стирания типа общая часть все равно теряется во время выполнения. Таким образом, во время выполнения невозможно различить
List
иList<String>
. Поэтому вы должны просто использоватьList.class
.3. Как упоминали другие, будет сложно получить больше информации, чем вы могли бы получить с помощью
List.class
. Информация о параметре типа будет потеряна. ОднакоTypeToken
класс Guava предлагает сложную инфраструктуру для такого рода задач, и вы, возможно, захотите взглянуть: code.google.com/p/guava-libraries/wiki/ReflectionExplained
Ответ №1:
Универсальный не знает и не заботится о том, чтобы был указан общий класс, и, как таковой, нет List<String>.class
, только List.class
. Вы рассматривали подстановочные знаки? Что должно List<?>.class
вернуться? И List<? extends AnotherClass>.class
? Итак, нет, вы не можете знать, какой конкретный класс содержит универсальный класс во время компиляции, в основном потому, что он может содержать разные классы, которые полностью указаны только во время выполнения.
Ответ №2:
Единственный способ записать обобщения для типа класса (и, следовательно, сделать их доступными во время выполнения с отражением) — это создать ваш подкласс GenericClass
. Даже анонимный внутренний класс выполняет эту работу:
GenericClass<List<String>> c = new GenericClass<List<String>>(...){};
(обратите внимание на завершение). {}
Комментарии:
1. Обратите внимание, что OP указывает «во время компиляции» .
2. Точно. Во время компиляции. Все анонимные внутренние классы создаются во время компиляции.
3. Во время компиляции средства
.class
должны работать.GenericClass<List<String>>.class
по-прежнему недопустимый синтаксис. То, что вы предлагаете, делаетGenericClass
абстрактным, извините, я не понимаю, как это решает проблему.4. Очевидно, я не могу изменить синтаксис java. Я только что объяснил, как записать общий параметр в байтовый код.
Ответ №3:
Как насчет:
public class GenericClass<T> {
Class<T> type;
@SuppressWarnings("unchecked")
public GenericClass() {
Type type = ((ParameterizedType) getClass()
.getGenericSuperclass()).getActualTypeArguments()[0];
if (type instanceof Class<?>)
this.type = (Class<T>)type;
else if (type instanceof ParameterizedType)
this.type = (Class<T>) ((ParameterizedType)type).getRawType();
else
this.type = null;
}
public Class<T> getType() {
return type;
}
}
Использование:
public static void main(String[] args) {
GenericClass<Integer> g = new GenericClass<Integer>() {};
System.out.println(g.getType());
GenericClass<List<String>> g2 = new GenericClass<List<String>>() {};
System.out.println(g2.getType());
}
Комментарии:
1. Обратите внимание на вопрос: «во время компиляции» .
2. Я думаю, что в названии вопроса упоминается время компиляции, потому что ошибка является ошибкой времени компиляции… Этот ответ предоставляет решение общей проблемы, которую пытаются решить, нет?
3. Я думаю, нет, потому что вопрос заключается в том, чтобы получить тип во время компиляции. Вы также можете свободно интерпретировать вопрос так, как вы это делали, все в порядке, я просто задаю правильный вопрос: D
4. «Мой вопрос заключается в следующем. Как я могу создать новый экземпляр класса с универсальным типом?» : p
5. В заголовке большими черными жирными буквами: «во время компиляции» : P
Ответ №4:
Ваша проблема в том, что существует только один List
объект класса, который вы можете получить List.class
. Но это Class<List>
, Class<List<Object>>
, Class<List<String>>
, или Class<List<?>>
и т.д.? Он может иметь только один тип, и разработчики Java выбрали Class<List>
(это единственный безопасный выбор). Если вы действительно хотите a Class<List<String>>
, вам придется выполнить несколько непроверенных приведений:
GenericClass<List<String>> c =
new GenericClass<List<String>>((Class<List<String>>)(Class<?>)List.class);