Класс <T> и статический метод Class.forName () сводят меня с ума

этот код не компилирует. Я задаюсь вопросом, что я делаю неправильно:

private static Importable getRightInstance(String s) throws Exception {
 Class<Importable> c = Class.forName(s);
 Importable i = c.newInstance();
 return i;
}

где Разрешенный к ввозу интерфейс, и строка s является названием класса с реализацией. В компиляторе говорится:

./Importer.java:33: incompatible types
found   : java.lang.Class<capture#964 of ?>
required: java.lang.Class<Importable>
  Class<Importable> c = Class.forName(format(s));

спасибо за любую справку!

Все решения

Class<? extends Importable> c = Class.forName(s).asSubclass(Importable.class);

и

Class<? extends Importable> c = (Class<? extends Importable>) Class.forName(s);

и

Class<?> c = Class.forName(format(s));
Importable i = (Importable)c.newInstance();

дайте эту ошибку (что я не понимаю):

Exception in thread "main" java.lang.IncompatibleClassChangeError: class C1 
has interface Importable as super class

где C1 на самом деле реализует Разрешенный к ввозу (таким образом, это теоретически castable к Разрешенному к ввозу).

10
задан Metz 23 May 2010 в 19:23
поделиться

5 ответов

Используйте преобразование во время выполнения:

Class <? extends Importable>  c
    = Class.forName (s).asSubclass (Importable.class);

Это будет лаять с исключением во время выполнения, если s указывает класс, который не реализует интерфейс.

32
ответ дан 3 December 2019 в 13:47
поделиться

где Importable - интерфейс, а строка s - имя реализующего класса.

Компилятор не может этого знать, отсюда и ошибка.

Используйте гипс. Проще привести построенный объект (потому что это проверенный тип), чем сам объект класса.

Class<?> c = Class.forName(s);
Importable i = (Importable) c.newInstance();
return i;
0
ответ дан 3 December 2019 в 13:47
поделиться

Что-то вроде этого может помочь:

Class<?> c1 = Class.forName(s);
Class<? extends Importable> c = c1.asSubclass(Importable.class);
return c.newInstance();

Остерегайтесь ClassCastException или NoClassDefFound , если вы передадите неправильный результат. Как говорит @polygenelubricants, если вы сможете найти способ избежать Class.forName , то тем лучше!

2
ответ дан 3 December 2019 в 13:47
поделиться

Проблема в том, что Class.forName - это статический метод со следующим определением

public static Class forName (String className) выдает исключение ClassNotFoundException

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

Если вы точно знаете, что имя строки, переданное в метод, будет реализацией интерфейса, вы можете использовать аннотацию SuppressWarnings. Но я не думаю, что есть другой более чистый способ использования forName с дженериками

0
ответ дан 3 December 2019 в 13:47
поделиться

Попробуйте:

Class<? extends Importable> klaz = Class.forName(s).asSubclass(Importable.class);

Вот несколько фрагментов, чтобы проиллюстрировать проблемы:

Class<CharSequence> klazz = String.class; // doesn't compile!
// "Type mismatch: cannot convert from Class<String> to Class<CharSequence>"

Однако:

Class<? extends CharSequence> klazz = String.class; // compiles fine!

Итак, для интерфейса вам определенно понадобится ограниченный сверху подстановочный знак. Подкласс asSubclass предложен doublep.

Ссылки API

  • Класс asSubclass (Class clazz)
    • Преобразует этот объект Class для представления подкласса класса, представленного указанным объектом класса. Проверяет, что приведение допустимо, и выдает исключение ClassCastException , если это не так. Если этот метод завершается успешно, он всегда возвращает ссылку на этот объект класса.

Связанные вопросы

См. Также

7
ответ дан 3 December 2019 в 13:47
поделиться
Другие вопросы по тегам:

Похожие вопросы: