我查看反射的所有示例都显示了创建未知实现的新实例,并将该实现强制转换为它的接口。这个问题是现在你不能在实现类上调用任何新方法(只有覆盖),因为你的对象引用变量具有接口类型。这就是我所拥有的:
Class c = null;
try {
c = Class.forName("com.path.to.ImplementationType");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
InterfaceType interfaceType = null;
try {
interfaceType = (InterfaceType)c.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
如果我只引用了“com.path.to.ImplementationType”,并且我不知道该类型是什么(它来自配置文件),那么我该如何使用类名来将它转换为ImplementationType?这甚至可能吗?
答案 0 :(得分:29)
这一行似乎总结了问题的症结所在:
这个问题是现在你不能在实现类上调用任何新方法(仅覆盖),因为你的对象引用变量具有接口类型。
您在当前的实现中非常困难,因为您不仅需要尝试强制转换,还需要定义要在此子类上调用的方法。我看到两个选择:
1。如其他地方所述,您不能使用类名称的String表示形式将反射的实例强制转换为已知类型。但是,您可以使用String
equals()
测试来确定您的类是否属于您想要的类型,然后执行硬编码演员:
try {
String className = "com.path.to.ImplementationType";// really passed in from config
Class c = Class.forName(className);
InterfaceType interfaceType = (InterfaceType)c.newInstance();
if (className.equals("com.path.to.ImplementationType") {
((ImplementationType)interfaceType).doSomethingOnlyICanDo();
}
} catch (Exception e) {
e.printStackTrace();
}
这看起来很丑陋,它破坏了你拥有的漂亮的配置驱动过程。我不建议你这样做,这只是一个例子。
2。您的另一个选择是将您的反思从Class
/ Object
创建扩展到包含Method
反射。如果您可以从配置文件传入的String中创建Class
,您还可以从该配置文件传入方法名称,并通过反射从您的配置中获取Method
本身的实例Class
对象。然后,您可以在invoke
上调用Method
(http://java.sun.com/javase/6/docs/api/java/lang/reflect/Method.html#invoke(java.lang.Object,java.lang.Object ...)),传入您创建的类的实例。我想这会帮助你了解你的目标。
以下是一些代码作为示例。请注意,我已经冒昧地对方法的参数进行了硬编码。您也可以在配置中指定它们,并且需要反映它们的类名以定义它们的Class
对象和实例。
public class Foo {
public void printAMessage() {
System.out.println(toString()+":a message");
}
public void printAnotherMessage(String theString) {
System.out.println(toString()+":another message:" + theString);
}
public static void main(String[] args) {
Class c = null;
try {
c = Class.forName("Foo");
Method method1 = c.getDeclaredMethod("printAMessage", new Class[]{});
Method method2 = c.getDeclaredMethod("printAnotherMessage", new Class[]{String.class});
Object o = c.newInstance();
System.out.println("this is my instance:" + o.toString());
method1.invoke(o);
method2.invoke(o, "this is my message, from a config file, of course");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException nsme){
nsme.printStackTrace();
} catch (IllegalAccessException iae) {
iae.printStackTrace();
} catch (InstantiationException ie) {
ie.printStackTrace();
} catch (InvocationTargetException ite) {
ite.printStackTrace();
}
}
}
和我的输出:
this is my instance:Foo@e0cf70
Foo@e0cf70:a message
Foo@e0cf70:another message:this is my message, from a config file, of course
答案 1 :(得分:3)
//====Single Class Reference used to retrieve object for fields and initial values. Performance enhancing only====
Class<?> reference = vector.get(0).getClass();
Object obj = reference.newInstance();
Field[] objFields = obj.getClass().getFields();
答案 2 :(得分:2)
作为akf答案的附录,您可以使用instanceof检查而不是String equals()调用:
String cname="com.some.vendor.Impl";
try {
Class c=this.getClass().getClassLoader().loadClass(cname);
Object o= c.newInstance();
if(o instanceof Spam) {
Spam spam=(Spam) o;
process(spam);
}
else if(o instanceof Ham) {
Ham ham = (Ham) o;
process(ham);
}
/* etcetera */
}
catch(SecurityException se) {
System.err.printf("Someone trying to game the system?%nOr a rename is in order because this JVM doesn't feel comfortable with: “%s”", cname);
se.printStackTrace();
}
catch(LinkageError le) {
System.err.printf("Seems like a bad class to this JVM: “%s”.", cname);
le.printStackTrace();
}
catch(RuntimeException re) {
// runtime exceptions I might have forgotten. Classloaders are wont to produce those.
re.printStackTrace();
}
catch(Exception e) {
e.printStackTrace();
}
注意一些值的自由硬编码。无论如何,要点是:
答案 3 :(得分:1)
您希望能够传入一个类并获得该类的类型安全实例吗?请尝试以下方法:
public static void main(String [] args) throws Exception {
String s = instanceOf(String.class);
}
public static <T> T instanceOf (Class<T> clazz) throws Exception {
return clazz.newInstance();
}
答案 4 :(得分:1)
我不能确定我的问题是否正确,但似乎你想要这样的事情:
Class c = null;
try {
c = Class.forName("com.path.to.ImplementationType");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
T interfaceType = null;
try {
interfaceType = (T) c.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
其中T可以在方法级别或类级别定义,即<T extends InterfaceType>
答案 5 :(得分:0)
如果您知道Class
的{{1}},则可以创建它的实例。所以你要做的就是不可能。