Как создать литерал класса известного типа: Class <List <String>>
Возьмите следующее:
public Class<List<String>> getObjectType() {
// what can I return here?
}
Какое выражение класса буквально можно вернуть из этого метода, который будет удовлетворять дженерикам и компилировать? List.class
не будет компилироваться, и не будет List.<String>class
.
Если вам интересно "почему", я пишу реализацию Spring FactoryBean<List<String>>
, которая требует от меня реализовать Class<List<String>> getObjectType()
. Однако это не вопрос Spring.
edit: Мои жалобные крики были услышаны полномочиями, которые находятся в SpringSource, поэтому Spring 3.0.1 будет иметь тип возврата getObjectType()
, измененный на Class<?>
, который аккуратно избегает проблемы.
Ответы
Ответ 1
Вы всегда можете использовать то, что вам нужно, например
return (Class<List<String>>) new ArrayList<String>().getClass();
или
return (Class<List<String>>) Collections.<String>emptyList().getClass();
Но я предполагаю, что не то, что вам нужно. Ну, это работает с предупреждением, но это не совсем "красиво".
Я только что нашел это
Почему нет литерала класса для подстановочных параметризованных типов?
Поскольку параметр с подстановочным знаком не имеет точного представления типа времени выполнения.
Так что кастинг может быть единственным способом.
Ответ 2
Вы никогда не должны использовать конструкцию Class<List<String>>
. Это бессмысленно и должно вызывать предупреждение на Java (но это не так). Экземпляры класса всегда представляют собой необработанные типы, поэтому вы можете иметь Class<List>
; это. Если вы хотите, чтобы что-то представляло тип reified generic типа List<String>
, вам нужен "маркер супер-типа", например, Guice:
http://google-guice.googlecode.com/git/javadoc/com/google/inject/TypeLiteral.html
Ответ 3
Существование a Class<List<String>>
является по своей сути опасным. вот почему:
// This statement generates a warning - for a reason...
Class<List<String>> unsafeListClass = (Class<List<String>>) (Class<?>) List.class;
List<Integer> integerList = new ArrayList<Integer>(); // Ok
integerList.add(42); // Ok
System.out.println(unsafeListClass.isInstance(integerList)); // Prints "true".
List<String> stringList =
unsafeListClass.cast(integerList); // Succeeds, with no warning!
stringList.add("Hello, World!"); // Also succeeds with no warning
for (int x: integerList) {
// Compiles without warning, but throws ClassCastException at runtime
System.out.println(100-x);
}
Ответ 4
Вы можете реализовать этот метод следующим образом:
public Class<List<String>> getObjectType() {
return (Class<List<String>>) ((Class)List.class);
}
Ответ 5
Нашел эту ссылку на странице springframework.org, которая дает некоторое представление.
например.
List<String> myList = new ArrayList<String>();
return (Class<List<String>>)myList.getClass();
Ответ 6
Ознакомьтесь с этим обсуждением на форумах SUN:
http://forums.sun.com/thread.jspa?threadID=5253007
И ссылка на сообщение в блоге, описывающее работу с помощью "маркеров супертекста":
http://gafter.blogspot.com/2006/12/super-type-tokens.html
Ответ 7
Я не уверен, что это возможно вообще, поскольку любой литерал класса будет скомпилирован в Class.forName(...)
, и так как это происходит во время выполнения, информация об общей информации отсутствует.
Ответ 8
Я не уверен, но следующий вопрос, который я задал, может иметь отношение к вам...
java генерирует параметры типа и операции над этими типами
Ответ 9
Как насчет этого:
public class TestMain {
public static void main(String[] args) throws Exception {
Type type = TestMain.class.getMethod("dummy").getGenericReturnType();
System.out.println("type = " + type);
}
public List<Integer> dummy() {return null;}
}
Отпечатки:
type = java.util.List<java.lang.Integer>
Ответ 10
Следующий подход проблематичен:
> public Class<List<String>> getModelType() {
> return (Class<List<String>>) new ArrayList<String>().getClass();
> }
например. если вы хотите проверить, говорит ли объект о типе
org.eclipse.emf.common.util.BasicEList<String>
имеет тип
List<String>
на основе результата вышеупомянутого подхода getModelType(), например:
BasicEList<String> fromObject = ...;
if (getModelType().isAssignableFrom(fromObject.getClass())) {
transferFromModelToUi(getModelType().cast(fromObject));
}
это приведет к false, тогда как это должно быть правдой, потому что оба объекта реализуют интерфейс List (поскольку getModelType() возвращает объект класса типа List, а не ArrayList).
Вот подход, который работал у меня (немного громоздкий, но приводит к правильным результатам в приведенном выше примере, может быть перенесен в статический инициализатор):
public Class<List<String>> getModelType() {
Class<?> arrayListClass = new ArrayList<String>().getClass();
Class<?>[] interfaces = arrayListClass.getInterfaces();
int index = 0;
for (int i = 0; i < interfaces.length; i++) {
if (interfaces[i].equals(List.class)) {
index = i;
break;
}
}
return (Class<List<String>>) interfaces[index];
}