且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

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

更新时间:2023-11-30 14:03:58

这一行似乎总结了您的问题的症结所在:

This line seems to sum up the crux of your problem:

问题在于,现在您无法在实现类上调用任何新方法(仅覆盖),因为您的对象引用变量具有接口类型.

The issue with this is that now you can't call any new methods (only overrides) on the implementing class, as your object reference variable has the interface type.

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

You are pretty stuck in your current implementation, as not only do you have to attempt a cast, you also need the definition of the method(s) that you want to call on this subclass. I see two options:

1. 如别处所述,您不能使用类名称的字符串表示将反射实例转换为已知类型.但是,您可以使用 String equals() 测试来确定您的类是否属于您想要的类型,然后执行硬编码转换:>

1. As stated elsewhere, you cannot use the String representation of the Class name to cast your reflected instance to a known type. You can, however, use a String equals() test to determine whether your class is of the type that you want, and then perform a hard-coded cast:

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

这看起来很丑陋,它破坏了您拥有的漂亮的配置驱动过程.我不建议你这样做,这只是一个例子.

This looks pretty ugly, and it ruins the nice config-driven process that you have. I dont suggest you do this, it is just an example.

2. 另一个选择是将反射从 Class/Object 创建扩展到包含 Method 反思.如果您可以从配置文件中传入的字符串创建 Class,您还可以从该配置文件中传入方法名称,并通过反射获取 Method 本身来自您的 Class 对象.然后您可以调用 invoke(http://java.sun.com/javase/6/docs/api/java/lang/reflect/Method.html#invoke(java.lang.Object,java.lang.Object...)) 在 Method 上,传入你创建的类的实例.我认为这将帮助你得到你想要的.

2. Another option you have is to extend your reflection from just Class/Object creation to include Method reflection. If you can create the Class from a String passed in from a config file, you can also pass in a method name from that config file and, via reflection, get an instance of the Method itself from your Class object. You can then call invoke(http://java.sun.com/javase/6/docs/api/java/lang/reflect/Method.html#invoke(java.lang.Object, java.lang.Object...)) on the Method, passing in the instance of your class that you created. I think this will help you get what you are after.

这里有一些代码作为示例.请注意,我冒昧地对方法的参数进行了硬编码.您也可以在配置中指定它们,并且需要反映它们的类名以定义它们的 Class 对象和实例.

Here is some code to serve as an example. Note that I have taken the liberty of hard coding the params for the methods. You could specify them in a config as well, and would need to reflect on their class names to define their Class obejcts and instances.

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