Class <t>和静态方法Class.forName()让我发疯了</t>

时间:2010-05-23 18:06:16

标签: java generics reflection

此代码无法编译。我想知道我做错了什么:

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实际上是实现可导入的(因此它理论上可以转换为可导入的)。

5 个答案:

答案 0 :(得分:32)

使用运行时转换:

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

如果s指定了一个没有实现接口的类,那么在运行时会出现异常。

答案 1 :(得分:7)

尝试:

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。如果此方法成功,则它始终返回对此类对象的引用。

相关问题

另见

答案 2 :(得分:2)

这样的事情可能会起到作用:

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

如果传入错误的内容,请注意ClassCastExceptionNoClassDefFound。正如@polygenelubricants所说,如果你能找到一些避免Class.forName的方法,那就更好了!

答案 3 :(得分:0)

问题是Class.forName是一个静态方法,具有以下定义

public static Class forName(String className)抛出ClassNotFoundException

因此它根本不是绑定参数类型,编译器肯定会抛出强制转换警告,因为它无法保证类的字符串名称总能为您提供接口的实现。

如果您确定传递给方法的字符串名称是接口的实现,则可以使用SuppressWarnings注释。但我不认为使用forName和泛型的任何其他更干净的方式

答案 4 :(得分:0)

  

其中Importable是一个接口,字符串s是实现类的名称。

编译器无法知道,因此错误。

使用演员。与类对象本身相比,构建对象(因为这是一个经过检查的强制转换)更容易。

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