этот код не компилирует. Я задаюсь вопросом, что я делаю неправильно:
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 к Разрешенному к ввозу).
Используйте преобразование во время выполнения:
Class <? extends Importable> c
= Class.forName (s).asSubclass (Importable.class);
Это будет лаять с исключением во время выполнения, если s
указывает класс, который не реализует интерфейс.
где Importable - интерфейс, а строка s - имя реализующего класса.
Компилятор не может этого знать, отсюда и ошибка.
Используйте гипс. Проще привести построенный объект (потому что это проверенный тип), чем сам объект класса.
Class<?> c = Class.forName(s);
Importable i = (Importable) c.newInstance();
return i;
Что-то вроде этого может помочь:
Class<?> c1 = Class.forName(s);
Class<? extends Importable> c = c1.asSubclass(Importable.class);
return c.newInstance();
Остерегайтесь ClassCastException
или NoClassDefFound
, если вы передадите неправильный результат. Как говорит @polygenelubricants, если вы сможете найти способ избежать Class.forName
, то тем лучше!
Проблема в том, что Class.forName - это статический метод со следующим определением
public static Class forName (String className) выдает исключение ClassNotFoundException
Следовательно, это вообще не связанный тип параметра и компилятор определенно выдаст предупреждение о приведении здесь, поскольку он не может гарантировать, что строковое имя класса всегда будет давать вам реализацию интерфейса.
Если вы точно знаете, что имя строки, переданное в метод, будет реализацией интерфейса, вы можете использовать аннотацию SuppressWarnings. Но я не думаю, что есть другой более чистый способ использования forName с дженериками
Попробуйте:
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.
Класс extends U> asSubclass (Class clazz)
Class
для представления подкласса класса, представленного указанным объектом класса. Проверяет, что приведение допустимо, и выдает исключение ClassCastException
, если это не так. Если этот метод завершается успешно, он всегда возвращает ссылку на этот объект класса.