Как создать литерал класса известного типа: Class <List <String>> - PullRequest
55 голосов
/ 06 января 2010

Возьмите следующее:

public Class<List<String>> getObjectType() {
    // what can I return here?
}

Какое литеральное выражение класса я могу вернуть из этого метода, который будет удовлетворять шаблонам и компилировать? List.class не скомпилируется и не будет List.<String>class.

Если вам интересно «почему», я пишу реализацию Spring * FactoryBean<List<String>>, которая требует от меня реализации Class<List<String>> getObjectType(). Однако это , а не весенний вопрос.

edit: Мои жалобные крики были услышаны силами, находящимися в SpringSource, и поэтому Spring 3.0.1 будет иметь тип возврата getObjectType(), измененный на Class<?>, который аккуратно избегает проблема.

Ответы [ 10 ]

42 голосов
/ 06 января 2010

Вы всегда можете привести к тому, что вам нужно, например,

return (Class<List<String>>) new ArrayList<String>().getClass();

или

return (Class<List<String>>) Collections.<String>emptyList().getClass();

Но я предполагаю, что это не то, что вам нужно. Ну, это работает, с предупреждением, но это не совсем "красиво".

Я только что нашел это

Почему нет литерала класса для параметризованных типов с подстановочными знаками?

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

Так что литье может быть единственным путем.

15 голосов
/ 06 января 2010

Никогда не используйте конструкцию Class<List<String>>. Это бессмысленно, и должно выдавать предупреждение в Java (но не делает). Экземпляры класса всегда представляют необработанные типы, поэтому вы можете иметь Class<List>; вот и все. Если вы хотите, чтобы что-то представляло расширенный универсальный тип, такой как List<String>, вам нужен «токен супертипа», который использует Guice:

http://google -guice.googlecode.com / мерзавец / Javadoc / COM / Google / впрыснуть / TypeLiteral.html

7 голосов
/ 12 февраля 2010

Существование 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);
}
6 голосов
/ 06 января 2010

Найдена эта ссылка на springframework.org, которая дает некоторое представление.

Например

List<String> myList = new ArrayList<String>();
return (Class<List<String>>)myList.getClass();
5 голосов
/ 13 апреля 2014

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

public Class<List<String>> getObjectType() {
    return (Class<List<String>>) ((Class)List.class);
}
2 голосов
/ 06 января 2010

Проверьте это обсуждение на форумах SUN:

http://forums.sun.com/thread.jspa?threadID=5253007

И упомянутое сообщение в блоге, которое описывает обходные пути с помощью «супер-токенов»:

http://gafter.blogspot.com/2006/12/super-type-tokens.html

1 голос
/ 06 января 2010

Я не уверен, возможно ли это вообще, так как любой литерал класса будет скомпилирован в Class.forName(...), и поскольку это происходит во время выполнения, общей информации не осталось.

0 голосов
/ 28 марта 2014

Следующий подход проблематичен:

> 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 () возвращает объект Class типа 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];
}
0 голосов
/ 09 мая 2013

Что по этому поводу:

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>
0 голосов
/ 06 января 2010

Я не уверен, но следующий вопрос, который я задал, может иметь отношение к вам ...

параметры типа java generics и операции над этими типами

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