Проблема отражения - Тип Предупреждение о безопасности - PullRequest
2 голосов
/ 26 мая 2010
Class<? extends Algorithm> alg = AlgorithmAllFrom9AndLastFrom10Impl.class   
Constructor<Algorithm> c = alg.getConstructors()[0];

Для "alg.getConstructors () [0];" Я получаю предупреждение в затмении

Тип безопасности: выражение типа Конструктор нуждается в непроверенном преобразовании соответствовать конструктору

Как мне это исправить?

Ответы [ 3 ]

10 голосов
/ 26 мая 2010

Документация для Class<T>.getConstructors() раскрывает проблему:

Constructor<?>[] getConstructors(): обратите внимание, что хотя этот метод возвращает массив объектов Constructor<T> (это массив конструкторов из этого класса), тип возвращаемого значения этого метода Constructor<?>[], а не Constructor<T>[] как и следовало ожидать. Этот менее информативный тип возвращаемого значения необходим, поскольку после возврата из этого метода массив можно изменить, чтобы он содержал Constructor объекты для различных классов, что нарушало бы гарантии типа Constructor<T>[].

Сравните это с Class<T>.getConstructor() перегрузкой:

Constructor<T> getConstructor(Class<?>... parameterTypes)

Эта перегрузка фактически возвращает Constructor<T>.

В вашем случае, поскольку у вас Class<? extends Algorithm> alg, alg.getConstructor(parameterTypes) возвращает Constructor<? extends Algorithm> (что, кстати, НЕ может быть безопасно приведено к Constructor<Algorithm>).

Когда это возможно, то есть когда вы знаете типы параметров, вы всегда должны предпочитать от getConstructor(parameterTypes) до getConstructors()[arbitraryIndex], так как с последними вы никогда не будете полностью уверены, какой конструктор будет выбран. Выбор, основанный на типах параметров, наиболее специфичен и, как показано здесь, также более удобен для компилятора в отношении информации об общем типе.

Если под getConstructors()[0] вы действительно хотели получить нулевой конструктор, просто сделайте это вместо:

Constructor<? extends Algorithm> nullaryConstructor = alg.getConstructor();

Резюме

Так что ваша проблема была в два раза:

  • getConstructors() возвращает Constructor<?>[], что означает потерю всей информации о типах
  • Даже если информация о типе не потеряна (например, при использовании перегрузки getConstructor(parameterTypes)), вы все равно получите в лучшем случае Constructor<? extends Algorithm> (не Constructor<Algorithm>).
    • Class<T>.getConstructor(parameterTypes) возвращает Constructor<T>
    • В вашем случае параметр типа T равен ? extends Algorithm

Смотри также

Смежные вопросы


Обсуждение

К сожалению, getConstructors() возвращает массив, потому что, как объяснено в документации, потому что, так как массивы ковариантны, это заставило подпись к Constructor<?>, потеряв информацию общего типа. Тот факт, что массивы являются изменяемыми, также означает, что getConstructors() должен каждый раз создавать новый экземпляр массива!

    System.out.println(int.class.getConstructors().length); // prints "0"
    System.out.println(
        int.class.getConstructors() == int.class.getConstructors()
    ); // prints "false"!

В идеале getConstructors() должно возвращать List<Constructor<T>>, которое должно быть заключено в Collections.unmodifiableList; это не только сохранит информацию о типе, но Class<T> может также возвращать один и тот же объект List на каждый getConstructors().

Подробнее об этом читайте в статье Effective Java 2nd Edition, пункт 25. Предпочитайте списки массивам .

0 голосов
/ 26 мая 2010

Массив Constructor, возвращаемый из getConstructors(), имеет неограниченный параметр типа подстановочного знака. Вы можете использовать:

Constructor<?> c = alg.getConstructors()[0];

Я предполагаю, что причина getConstructors() не ограничивает его подстановочный знак, потому что это приведет к универсальному массиву Возможно, один из методов getConstructor() лучше подходит для того, что вам нужно.

0 голосов
/ 26 мая 2010

На самом деле без приведения к Constructor<Algorithm> Я получаю ошибку.

Одним из решений является выполнение Constructor<?> c = alg.getConstructors()[0];, поскольку именно этот тип возвращает getConstructors ().

Другой способ - добавить @SuppressWarnings("unchecked") к этой строке, в основном говоря компилятору: «Я точно знаю, что это Constructor<Algorithm>», что компилятор не может сказать.

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