我想通过String的值来实例化一个类。我找到了几个教程,展示了这样做的几种方法。该类必须从某个接口ImplementMe
继承,该接口有一个名为runMe()
的特殊方法。所以这就是我的尝试:
ImplmentMe a =
(ImplementMe) ImplementMe.class
.getClassLoader()
.loadClass("my.package.IImplementedYou")
.newInstance();
a.runMe();
它有效,但它太丑了。我至少预计不需要演员。请告诉我有更好的方法。
答案 0 :(得分:34)
不,没有更好的方法(按设计)。你不应该这样做,Java被设计为一种类型安全的语言。但是,我可以理解你有时需要做这样的事情,为此你可以创建一个像这样的库函数:
public <T> T instantiate(final String className, final Class<T> type){
try{
return type.cast(Class.forName(className).newInstance());
} catch(InstantiationException
| IllegalAccessException
| ClassNotFoundException e){
throw new IllegalStateException(e);
}
}
现在您的客户端代码至少可以调用此方法而不进行强制转换:
MyInterface thingy =
instantiate("com.foo.bar.MyInterfaceImpl", MyInterface.class);
答案 1 :(得分:11)
尝试Class.forName("my.package.IImplementedYou")
。
答案 2 :(得分:6)
我将如何做到这一点:
ImplementMe noCastNeeded =
this.getClassLoader()
.loadClass("my.package.IImplementedYou")
.asSubclass(ImplementMe.class).newInstance();
有一些例外可以捕获,但我认为这没关系。 :)
答案 3 :(得分:2)
无论您是否使用第三方工具包,都会发生这种情况。 除非期待Object
,否则强制转换对象本身就是强制性的。但是,您可以为您做一个例行程序:
public <T> T instantiateObject(String name, Class<T> cls) throws Exception {
return (T) Class.forName(name).newInstance();
}
您可以使用:
AClass cls = instantiateObject("com.class.AClass", AClass.class);
但是如果你走到这一步,String name
实际上是多余的(假设AClass是一个具体的类)。你可能也是这样:
public <T> T instantiateObject(Class<T> cls) throws Exception {
return (T) Class.forName(cls.getCanonicalName()).newInstance();
}
您可以使用:
AClass cls = instantiateObject(AClass.class);
答案 4 :(得分:1)
你可以缩短它有点像
ImplementMe a = (ImplementMe) Class
.forName("my.package.IImplementedYou")
.newInstance();
但是你无法摆脱演员阵容。可能有一种方法可以避免强制转换,但前提是你可以避免按名称加载类的子问题。
答案 5 :(得分:1)
另一种方法是使用forName
,但它并没有比你现有的更好:
ImplementMe a =
(ImplementMe) Class.forName("my.package.IImplementedYou").newInstance();
a.runMe();
事实上,forName
将在幕后使用getClassLoader().loadClass()
来加载课程,您可以在Class.java
的 source code 中看到。
答案 6 :(得分:0)
您将需要强制转换,因为编译器无法从代码中判断出该对象的类型为ImplementMe。因此,它需要程序员发出一个强制转换,如果该对象不是一个ImplementMe实例,它将抛出一个ClassCastException。
答案 7 :(得分:0)
您所拥有的可能有用,但您不必使用加载ImplementMe的相同类加载器加载该类。这应该同样有效:
Object newInstance = this.getClass().getClassLoader().loadClass("my.package.IImplementedYou").newInstance();
重要的是,类加载器知道带有“my.package.IImplementedYou”实现的类文件和带有“ImplementMe”实现的类。
您可以明确检查IImplementedYou是否真的像这样实现了ImplementMe:
if(newInstance instanceof my.package.IImplementedYou) {
((ImplementMe)newInstance).runMe();
}
您还可以在创建实例之前检查IImlementedYou是否真正在实现接口:
Class c = this.getClass().getClassLoader().loadClass("my.package.IImplementedYou");
if(ImplementMe.class.isAssignableFrom(c)) {
Object newInstance = c.newInstance();
}
答案 8 :(得分:-1)
(MyInterface)Class.forName(className).newInstance()