scala 使用构造函数参数通过反射实例化对象

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1641104/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 01:42:30  来源:igfitidea点击:

instantiate object with reflection using constructor arguments

reflectionscala

提问by justin

I'm trying to figure out how to instantiate a case class object with reflection. Is there any support for this? The closest I've come is looking at scala.reflect.Invocation, but this seems more for executing methods that are a part of an object.

我想弄清楚如何用反射实例化一个案例类对象。是否有任何支持?我最接近的是查看 scala.reflect.Invocation,但这似乎更适合执行作为对象一部分的方法。

case class MyClass(id:Long, name:String)

def instantiate[T](className:String)(args:Any*) : T = { //your code here }

Is close to the API I'm looking for.

接近我正在寻找的 API。

Any help would be appreciated.

任何帮助,将不胜感激。

回答by michael.kebe

scala> case class Foo(id:Long, name:String)
defined class Foo

scala> val constructor = classOf[Foo].getConstructors()(0)
constructor: java.lang.reflect.Constructor[_] = public Foo(long,java.lang.String)

scala> val args = Array[AnyRef](new java.lang.Integer(1), "Foobar")
args: Array[AnyRef] = Array(1, Foobar)

scala> val instance = constructor.newInstance(args:_*).asInstanceOf[Foo]
instance: Foo = Foo(1,Foobar)

scala> instance.id
res12: Long = 1

scala> instance.name
res13: String = Foobar

scala> instance.getClass
res14: java.lang.Class[_] = class Foo

Currently there is not much reflection support in Scala. But you can fall back to th Java Reflection API. But there are some obstacles:

目前 Scala 中没有太多反射支持。但是您可以退回到 Java 反射 API。但是有一些障碍:

  • You have to create a Array[AnyRef]and box your "primitive types" in the wrapper classes (java.lang.Integer, java.lang.Character, java.lang.Double, ...)

  • newInstance(Object ... args)gets an varargs array of Object, so you should give the type inferer a hint with :_*

  • newInstance(...)returns an Objectso you have to cast it back with asInstanceOf[T]

  • 您必须Array[AnyRef]在包装类 ( java.lang.Integer, java.lang.Character, java.lang.Double, ...) 中创建一个并装箱您的“原始类型”

  • newInstance(Object ... args)得到一个可变参数数组Object,所以你应该给类型推断器一个提示:_*

  • newInstance(...)返回一个Object所以你必须把它扔回去asInstanceOf[T]

The closest I could get to your instantiatefunction is this:

我能得到的最接近你的instantiate功能是这样的:

def instantiate(clazz: java.lang.Class[_])(args:AnyRef*): AnyRef = {
  val constructor = clazz.getConstructors()(0)
  return constructor.newInstance(args:_*).asInstanceOf[AnyRef]
}

val instance = instantiate(classOf[MyClass])(new java.lang.Integer(42), "foo")
println(instance)           // prints: MyClass(42,foo)
println(instance.getClass)  // prints: class MyClass

You cannot get the get class from a generic type. Java erases it (type erasure).

您无法从泛型类型获取 get 类。Java 擦除它(类型擦除)。

Edit: 20 September 2012

编辑:2012 年 9 月 20 日

Three years on, the instantiatemethod can be improved to return a properly typed object.

三年过去了,instantiate可以改进该方法以返回正确类型的对象。

def instantiate[T](clazz: java.lang.Class[T])(args:AnyRef*): T = {
  val constructor = clazz.getConstructors()(0)
  return constructor.newInstance(args:_*).asInstanceOf[T]
}

See http://www.nabble.com/How-do-I-get-the-class-of-a-Generic--td20873455.html

http://www.nabble.com/How-do-I-get-the-class-of-a-Generic--td20873455.html

回答by Eugene Yokota

See answers to Scala: How do I dynamically instantiate an object and invoke a method using reflection?as well, especially regarding type erasure.

请参阅Scala 的答案:如何使用反射动态实例化对象并调用方法?同样,尤其是在类型擦除方面。

回答by justin

This is what I've ended up with so far, I'd like to not have to deal directly with AnyRef if possible. So if anyone knows a way to get around that I'd appreciate the help.

到目前为止,这就是我最终得到的结果,如果可能的话,我不想直接与 AnyRef 打交道。因此,如果有人知道解决方法,我将不胜感激。

case class MyClass(id:Long,name:String)

def instantiate[T](classArgs: List[AnyRef])(implicit m : Manifest[T]) : T ={
      val constructor = m.erasure.getConstructors()(0)
      constructor.newInstance(classArgs:_*).asInstanceOf[T]
    }

val list = List[AnyRef](new java.lang.Long(1),"a name")
val result = instantiate[MyClass](list)
println(result.id)