如何使用TypeTags在运行时创建类型为T的实例

时间:2014-02-11 23:09:58

标签: scala reflection

下面是如何使用Manifest在运行时创建类型为T的新实例:

trait MyTrait
class MyClass1(val name: String) extends MyTrait
class MyClass2(val name: String) extends MyTrait

class Test[T <: MyTrait] {

  def createInstance[T](name: String)(implicit m: Manifest[T]): T = {
    m.runtimeClass.getConstructors()(0)
      .newInstance(name).asInstanceOf[T]
  }

  def doSomething() {
    val myClass = createInstance("joe")
    ...
  }
}

...

val test = new Test[MyClass1]
test.doSomething

上面的createInstance方法创建了一个实现MyTrait的类的新实例,并使用给定的字符串调用构造函数。如何使用TypeTag实现相同的功能?


使用scala.reflect.runtime重新实现._

以下是按照som-snytt的建议重新实现的课程Test

class Test[T <: MyTrait] {

  import scala.reflect.runtime._
  import scala.reflect.runtime.universe._

  def createInstance[T: TypeTag](name: String): T = {
    val tt = typeTag[T]

    currentMirror.reflectClass(tt.tpe.typeSymbol.asClass).reflectConstructor(
      tt.tpe.members.filter(m =>
        m.isMethod && m.asMethod.isConstructor
      ).iterator.next.asMethod
    )(name).asInstanceOf[T]
  }   
}

只要我在createInstance上致电Test就可以了:

val test = new Test[MyClass1]
val myClass = test.createInstance("hello") // this works

但是一旦我定义了一个派生自Test ...

的新类
class DerivedTest[T <: MyTrait] extends Test[T]

...我在这个新类上调用createInstance ......

val test = new DerivedText[MyClass1]
val myClass = test.createInstance("hello") // this crashes

...我收到以下错误:

java.util.NoSuchElementException: next on empty iterator
    at scala.collection.Iterator$$anon$2.next(Iterator.scala:39)
    at scala.collection.Iterator$$anon$2.next(Iterator.scala:37)
    at scala.collection.LinearSeqLike$$anon$1.next(LinearSeqLike.scala:62)
    at DerivedTest$class.createInstance(<console>:27)
    at $anon$1.createInstance(<console>:26)
    at .<init>(<console>:28)
at .<clinit>(<console>)
    at .<init>(<console>:7)
    at .<clinit>(<console>)
    at $print(<console>)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
...

我错过了什么吗?

4 个答案:

答案 0 :(得分:6)

最终这是实际可行的实现 - 请假设此答案来自 som-snytt

import scala.reflect.runtime._
import scala.reflect.runtime.universe._

class Test[T <: MyTrait : TypeTag] {

  def createInstance(args: AnyRef*)(ctor: Int = 0): T = {
    val tt = typeTag[T]

    currentMirror.reflectClass(tt.tpe.typeSymbol.asClass).reflectConstructor(
      tt.tpe.members.filter(m =>
        m.isMethod && m.asMethod.isConstructor
      ).iterator.toSeq(ctor).asMethod
    )(args: _*).asInstanceOf[T]
  }   
}

我希望有所帮助。

答案 1 :(得分:4)

也许有人一直这样做可以插话,但我花了很多步骤来重现它。

我启动了REPL -i,因此自动完成功能被破坏了。这让我处于劣势。

scala> class X(i: Int)
defined class X

scala> typeTag[X]
res0: reflect.runtime.universe.TypeTag[X] = TypeTag[X]

scala> .tpe
res1: reflect.runtime.universe.Type = X

scala> .members
res2: reflect.runtime.universe.MemberScope = Scopes(constructor X, value i, method $asInstanceOf, method $isInstanceOf, method synchronized, method ##, method !=, method ==, method ne, method eq, constructor Object, method notifyAll, method notify, method clone, method getClass, method hashCode, method toString, method equals, method wait, method wait, method wait, method finalize, method asInstanceOf, method isInstanceOf, method !=, method ==)

scala> res2.filter(s => s.isMethod && s.asMethod.isConstructor)
res4: Iterable[reflect.runtime.universe.Symbol] = SynchronizedOps(constructor X, constructor Object)

scala> res4.iterator.next
res7: reflect.runtime.universe.Symbol = constructor X

scala> .typeSignature
res8: reflect.runtime.universe.Type = (i: scala.Int)X

scala> res7.asMethod
res11: reflect.runtime.universe.MethodSymbol = constructor X

scala> res1.typeSymbol.asClass
res13: reflect.runtime.universe.ClassSymbol = class X

scala> currentMirror reflectClass res13
res14: reflect.runtime.universe.ClassMirror = class mirror for X (bound to null)

scala> res14 reflectConstructor res11
res16: reflect.runtime.universe.MethodMirror = constructor mirror for X.<init>(i: scala.Int): X (bound to null)

scala> res16(7)
res17: Any = X@28730c5a

scala> .asInstanceOf[X]
res18: X = X@28730c5a

答案 2 :(得分:2)

J3D,

我认为清单方法已被弃用。 您可以使用下面的scala代码通过反射创建实例。 您将不得不稍微调整代码以考虑具有多个构造函数和/或参数

的类

代码基于http://docs.scala-lang.org/overviews/reflection/overview.html

import scala.reflect.runtime.{universe => ru}
import ru._

...

class Person { }


def example() = 
{
   val instance1 = createInstance[Person]()
   val instance2 = createInstance(typeOf[Person])
}


def createInstance[T:TypeTag]() : Any= {
    createInstance(typeOf[T])
}


def createInstance(tpe:Type): Any = {
    val mirror = ru.runtimeMirror(getClass.getClassLoader)
    val clsSym = tpe.typeSymbol.asClass
    val clsMirror = mirror.reflectClass(clsSym)
    val ctorSym = tpe.decl(ru.termNames.CONSTRUCTOR).asMethod
    val ctorMirror = clsMirror.reflectConstructor(ctorSym)
    val instance = ctorMirror()
    return instance
}

答案 3 :(得分:0)

object BeanFactory {

  import scala.reflect.runtime.universe._
  import scala.reflect.runtime.{universe => ru}

  def createBean[T: TypeTag](): Option[T] = {
    val typee = ru.typeOf[T]
    val constructor = typee.decl(ru.termNames.CONSTRUCTOR).asMethod
    if (constructor.isPrivate) {
      println("private class can not created ")
      None
    } else {
      val classMirror = ru.runtimeMirror(getClass.getClassLoader).reflectClass(typee.typeSymbol.asClass)
      val constructorMethod = classMirror.reflectConstructor(constructor)
      val params = constructor.paramLists.flatten.map(par => {
        if (par.typeSignature =:= typeOf[Int]) {
          0
        } else {
          if (par.typeSignature =:= typeOf[String]) {
            ""
          } else {
            if (par.typeSignature =:= typeOf[Double]) {
              0.0
            } else {
              if (par.typeSignature =:= typeOf[Float]) {
                0.0f
              } else {
                if (par.typeSignature =:= typeOf[Char]) {
                  ""
                } else {
                  if (par.typeSignature =:= typeOf[Boolean]) {
                    false
                  } else {
                    null
                  }
                }
              }
            }
          }
        }

      })
      Some(constructorMethod(params: _*).asInstanceOf[T])
    }
  }
}

这可能会因您的问题而结束