Java приведение ".class" -оператора, используемого в универсальном типе, например List, в "Class> "а к" класс" - PullRequest
17 голосов
/ 21 сентября 2011

Я использую оператор .class для предоставления информации о содержащемся типе в универсальный класс. Для неуниверсальных содержащихся типов, например, Integer.class, это работает без проблем. Но с содержащимся типом, являющимся универсальным, например, List<Integer>.class или List.class это приводит к ошибкам времени компиляции при приведении класса.

Есть способ обойти ошибки, но мне любопытно, что здесь происходит. Может кто-нибудь объяснить, что происходит? Почему все так, как есть? И какой лучший способ обойти проблему?

Следующие строки демонстрируют проблему: Обратите внимание, что внешний универсальный тип ожидает Class<T> в качестве параметра, поэтому в этом случае Class<List<Integer>>.

Class<Integer> tInt = Integer.class;                     // Works as expected.
Class<List> tList = List.class;              // Works with warning, but is not
                                             // what i'm looking for.
Class<List<Integer>> tListInt1 = List.class;                          // Error
Class<List<Integer>> tListInt2 = (Class<List<Integer>>) List.class;   // Error
Class<List<?>> tListGeneric = (Class<List<Integer>>) List.class;      // Error

Следующая строка работает:

Class<List<Integer>> tListInt3 = 
                (Class<List<Integer>>) ((Class<Integer>)List.class);

Почему объявления tListInt2 и tListGeneric дают и дают ошибку? Почему upcast, а затем downcast с tListInt3 не выдает ошибку? Есть ли лучший способ объявить tListInt3?

С уважением,
Каспер ван ден Берг

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

1 Ответ

27 голосов
/ 21 сентября 2011
Class<List<Integer>> tListInt3 = 
            (Class<List<Integer>>) ((Class<Integer>)List.class);

это не работает. Вы, вероятно, имели в виду

Class<List<Integer>> tListInt3 = 
            (Class<List<Integer>>) ((Class)List.class);

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

    Integer x = (Integer)(Object)"string";

Тип List.class равен Class<List>; это не подтип / супертип Class<List<Whatever>>, поэтому прямое приведение между двумя типами недопустимо.

Можно утверждать, что Class<List<Integer>> не существует - существует только класс для List; для List<Integer> такого класса нет (который на самом деле просто List во время выполнения)

Однако, это недостаток системы типов Java; на практике нам нужны такие вещи, как Class<List<Integer>>. Наше решение - кастовать и притворяться Class<List<Int>> выходами - также ошибочно - но это не наша вина.

...