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

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

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

где Importable - это интерфейс, а строка 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 фактически реализует Importable (поэтому он теоретически применим к Importable).

Ответ 1

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

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

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

Ответ 2

Try:

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!

Итак, для interface вам определенно нужен шаблон с верхним ограничением. asSubclass соответствует предложению doublep.

Ссылки API

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

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

См. также

Ответ 3

Что-то вроде этого может сделать трюк:

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

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

Ответ 4

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

public static Класс forName (String className) бросает ClassNotFoundException

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

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

Ответ 5

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

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

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

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