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

时间:2009-10-29 01:11:19

标签: reflection scala

我试图找出如何用反射实例化一个case类对象。这有什么支持吗?我最接近的是查看scala.reflect.Invocation,但这似乎更适合执行作为对象一部分的方法。

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

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

接近我正在寻找的API。

任何帮助都将不胜感激。

3 个答案:

答案 0 :(得分:19)

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

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

  • 您必须在包装类(Array[AnyRef]

  • 中创建java.lang.Integer, java.lang.Character, java.lang.Double, ...并打包“基本类型”
  • newInstance(Object ... args)获取Object的varargs数组,因此您应该为类型提供者提供:_*

  • 的提示
  • newInstance(...)返回Object,因此您必须使用asInstanceOf[T]

  • 将其强制转回

我最接近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

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

编辑:2012年9月20日

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

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

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

答案 1 :(得分:3)

答案 2 :(得分:2)

这是我到目前为止所得到的,如果可能的话,我不想直接与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)