Класс <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;