在 Java 中使用反射创建一个新实例,并将引用变量类型设置为新实例类名? [英] Using reflection in Java to create a new instance with the reference variable type set to the new instance class name?

查看:17
本文介绍了在 Java 中使用反射创建一个新实例,并将引用变量类型设置为新实例类名?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

All the examples I look at for reflection show creating a new instance of an unknown implementation, and casting that implementation to it's interface. 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. Here is what I have:

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

If I only have a reference to "com.path.to.ImplementationType", and I don't know what that type might be (it is coming from a config file), then how can I use the class name to cast it to ImplementationType? Is this even possible?

推荐答案

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

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<的实例/code> 本身来自您的 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

这篇关于在 Java 中使用反射创建一个新实例,并将引用变量类型设置为新实例类名?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆