Scala:如何动态实例化对象并使用反射调用方法?
在 Scala 中,动态实例化对象并使用反射调用方法的最佳方式是什么?
我想做以下 Java 代码的 Scala 等效项:
Class class = Class.forName("Foo");
Object foo = class.newInstance();
Method method = class.getMethod("hello", null);
method.invoke(foo, null);
在上面的代码中,类名和方法名都是动态传入的。上述 Java 机制可能适用于 Foo
和 hello()
,但 Scala 类型与 Java 类型并不一一匹配。例如,可以为单例对象隐式声明一个类。 Scala 方法还允许使用各种符号作为其名称。两者都是通过名称修改来解决的。请参阅 Java 和 Scala 之间的互操作。
另一个问题似乎是通过解决重载和自动装箱来匹配参数,如 来自 Scala 的反思 - 天堂与地狱。
In Scala, what's the best way to dynamically instantiate an object and invoke a method using reflection?
I would like to do Scala-equivalent of the following Java code:
Class class = Class.forName("Foo");
Object foo = class.newInstance();
Method method = class.getMethod("hello", null);
method.invoke(foo, null);
In the above code, both the class name and the method name are passed in dynamically. The above Java mechanism could probably be used for Foo
and hello()
, but the Scala types don't match one-to-one with that of Java. For example, a class may be declared implicitly for a singleton object. Also Scala method allows all sorts of symbols to be its name. Both are resolved by name mangling. See Interop Between Java and Scala.
Another issue seems to be the matching of parameters by resolving overloads and autoboxing, described in Reflection from Scala - Heaven and Hell.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
有一种更简单的方法来反射调用方法,而无需调用 Java 反射方法:使用结构类型。
只需将对象引用转换为具有必要方法签名的结构类型,然后调用该方法:不需要反射(当然,Scala 在下面进行反射,但我们不需要这样做)。
There is an easier way to invoke method reflectively without resorting to calling Java reflection methods: use Structural Typing.
Just cast the object reference to a Structural Type which has the necessary method signature then call the method: no reflection necessary (of course, Scala is doing reflection underneath but we don't need to do it).
VonC 和 Walter Chang 非常好,所以我将补充一项 Scala 2.8 实验功能。事实上,我什至懒得去打扮它,我只是复制 scaladoc。
The answers by VonC and Walter Chang are quite good, so I'll just complement with one Scala 2.8 Experimental feature. In fact, I won't even bother to dress it up, I'll just copy the scaladoc.
实例化部分可以使用清单:请参阅此SO答案
因此真正的类型安全解决方案将使用工厂。
注意:正如此线程中所述,Manifest 会保留下来,但目前“唯一的用途是提供对作为类实例的类型的擦除”。
然后可以通过反射得到一个方法:
并调用它
The instanciation part could use the Manifest: see this SO answer
So the true type safe solution would be using a Factory.
Note: as stated in this thread, Manifest is here to stay, but is for now "only use is to give access to the erasure of the type as a Class instance."
You can then get a method through reflection:
and invoke it
如果您需要调用 Scala 2.10 对象(不是类)的方法,并且方法和对象的名称为
String
,您可以这样做:这将打印
5
到标准输出。更多详细信息请参见 Scala 文档。
In case you need to invoke a method of a Scala 2.10 object (not class) and you have the names of the method and object as
String
s, you can do it like this:This prints
5
to standard output.Further details in Scala Documentation.
根据 @nedim 的回答,这是完整答案的基础,
主要区别在于下面我们实例化朴素类。该代码不处理多个构造函数的情况,并且绝不是完整的答案。
这是一个可以编译它的
build.sbt
:Working up from @nedim's answer, here is a basis for a full answer,
main difference being here below we instantiate naive classes. This code does not handle the case of multiple constructors, and is by no means a full answer.
Here is a
build.sbt
that would compile it: