使用Java中的反射创建一个引用变量类型设置为新实例类名的新实例?

使用Java中的反射创建一个引用变量类型设置为新实例类名的新实例?,java,reflection,Java,Reflection,我查看的所有反射示例都显示了创建未知实现的新实例,并将该实现强制转换到其接口。问题是,现在您不能在实现类上调用任何新方法(仅重写),因为您的对象引用变量具有接口类型。以下是我所拥有的: Class c = null; try { c = Class.forName("com.path.to.ImplementationType"); } catch (ClassNotFoundException e) { e.printStackTrace(); } InterfaceType

我查看的所有反射示例都显示了创建未知实现的新实例,并将该实现强制转换到其接口。问题是,现在您不能在实现类上调用任何新方法(仅重写),因为您的对象引用变量具有接口类型。以下是我所拥有的:

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

如果您知道
ImplementationType
类,您可以创建它的实例。因此,您尝试执行的操作是不可能的。

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

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();
}
publicstaticvoidmain(字符串[]args)引发异常{
String s=instanceOf(String.class);
}
公共静态T instanceOf(类clazz)引发异常{
返回clazz.newInstance();
}

这一行似乎概括了问题的症结:

问题是,现在您不能在实现类上调用任何新方法(仅重写),因为您的对象引用变量具有接口类型

您在当前的实现中陷入了困境,因为您不仅需要尝试强制转换,还需要定义要在这个子类上调用的方法。我看到两种选择:

1。如其他地方所述,不能使用类名的字符串表示将反射实例强制转换为已知类型。但是,您可以使用
字符串
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.另一个选择是将反射从仅创建
/
对象扩展到包含
方法
反射。如果可以从配置文件传入的字符串创建
,那么还可以从该配置文件传入方法名,并通过反射从
对象获取
方法
本身的实例。然后,您可以在
方法上调用
invoke
(,java.lang.Object…),传入您创建的类的实例。我想这会帮助你得到你想要的

下面是一些代码作为示例。请注意,我冒昧地对这些方法的参数进行了硬编码。您也可以在配置中指定它们,并且需要考虑它们的类名来定义它们的
class
obejcts和实例

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

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

    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可以在方法级或类级定义,即作为akf答案的补充,您可以使用instanceof checks而不是String equals()调用:

注意一些值的自由硬编码。总之,要点是:

  • 使用instanceof而不是equals()。如果有什么不同的话,它在重构时会更好地合作
  • 确保捕获这些运行时错误和安全错误
  • //==用于检索字段和初始值的对象的单个类引用。仅性能增强===
    类引用=vector.get(0.getClass();
    Object obj=reference.newInstance();
    字段[]objFields=obj.getClass().getFields();
    
    这就是我如何解决从未知类中检索信息创建新实例以使用其字段进行另一个通用搜索(按字段/值和/或过滤器)的问题的方法。忘记“performance”注释吧,它与后面几行有关。我在哪里可以下载方法
    InterfaceType
    ImplementationType
    的jar?
    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();
    }
    
    //====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();