使用Java中的reflection创建一个新实例,并将引用变量类型设置为新的实例类名称?

我查看reflection的所有示例都显示了创建未知实现的新实例,并将该实现强制转换为它的接口。 这个问题是现在你不能在实现类上调用任何新方法(仅覆盖),因为你的对象引用变量具有接口类型。 这是我有的:

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? 这有可能吗?

这条线似乎总结了你的问题的关键:

这个问题是现在你不能在实现类上调用任何新方法(仅覆盖),因为你的对象引用变量具有接口类型。

您现在的实现非常困难,因为您不仅需要尝试强制转换,还需要定义要在此子类上调用的方法。 我看到两个选择:

1.如其他地方所述,您不能使用类名称的String表示forms将reflection的实例强制转换为已知类型。 但是,您可以使用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.您的另一个选择是将您的reflection从仅仅Class / Object创建扩展到包括Methodreflection。 如果可以从从配置文件传入的String创建Class ,则还可以从该配置文件传入方法名称,并通过reflection从Class对象获取Method本身的实例。 然后你可以调用invokehttp://java.sun.com/javase/6/docs/api/java/lang/reflect/Method.html#invoke (java.lang.Object,java.lang.Object … ))在Method ,传入您创建的类的实例。 我想这会帮助你获得你想要的东西。

以下是一些代码作为示例。 请注意,我已经冒险对方法的参数进行硬编码。 您也可以在配置中指定它们,并且需要反映它们的类名以定义它们的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 
 //====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(); 

作为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(); } 

注意一些值的自由硬编码。 无论如何,要点是:

  1. 使用instanceof而不是equals()。 如果有的话,它会在重构时更好地合作。
  2. 一定要抓住这些运行时错误和安全性错误。

您希望能够传入一个类并获得该类的类型安全实例吗? 请尝试以下方法:

 public static void main(String [] args) throws Exception { String s = instanceOf(String.class); } public static  T instanceOf (Class clazz) throws Exception { return clazz.newInstance(); } 

我不完全确定我的问题是否正确,但似乎你想要这样的东西:

  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可以在方法级别或类级别定义,即

如果您知道Class of ImplementationType ,则可以创建它的实例。 所以你要做的就是不可能。