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

查看:102
本文介绍了使用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.

你在当前的实现中非常困难,因为你不仅需要尝试演员,还需要方法的定义( s)你想要调用这个子类。我看到两个选项:

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。您的另一个选择是扩展您的反射,只需 / 对象创建,以包含方法 reflection。如果你可以从配置文件传入的String创建 Class ,你也可以从该配置传入一个方法名称文件,并通过反射,从您的对象中获取方法本身的实例。然后您可以调用调用 http://java.sun。 上的com / javase / 6 / docs / api / java / lang / reflect / Method.html #invoke(java.lang.Object ,java.lang.Object ...))方法,传入您创建的类的实例。我想这会帮助你了解你的目标。

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 obejcts和实例。

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天全站免登陆