在运行时使用默认构造函数实例化类型参数化 class

Instantiate type-parametrized class at runtime with default constructor

我想用以下 classes 实例化一个新对象:

class Test[T : ClassTag](val value : T) extends Serializable

private object Test {
  private var testClass : Class[_] = _

  def setTestClass(test : Class[_]) : Unit = {
    testClass = test
  }

  def apply[T : ClassTag](value : T) : Test[T] = {
    testClass.getConstructors()(0).newInstance(value).asInstanceOf[Test[T]]
  }
}

class Subtest[T : ClassTag](
    override val value : T, 
    val additional : Integer
) extends Test[T](value)

我在某处设置了 test-class 和 setTestClass,它已经从字符串中加载了 Class.forName。假设它是 "Subtest"。我希望用以下代码实例化一个新的 Subtest[String]

Test("my random string") // It should return a new Subtest[String]

问题是 newInstance 抛出 java.lang.IllegalArgumentException: wrong number of arguments。我检查了ConstructorparameterTypes,有两种参数类型:

好的。如何提供 ClassTag?这里有什么问题? 有没有更好的方法和解决方法?

T: ClassTag 语法称为 上下文绑定 。它是 ClassTag[T] 类型隐式参数的语法糖。换句话说,以下 class 个签名是等价的:

class Test[T : ClassTag](val value : T)
class Test[T](val value: T)(implicit val ev: ClassTag[T])

所以您正在寻找的构造函数需要另一个参数。使用上下文绑定语法时,您始终可以使用 implicitly 来获取所需的参数(由于上下文绑定的语义,保证存在)。或者,您可以使用 classTag 运算符直接获取 ClassTag[T] 的实例,当您知道它可用时。

另一个细节是,在像这样的对象中使用类型参数时,它需要是一个AnyRef

因此您的 apply 方法可能如下所示:

def apply[T <: AnyRef : ClassTag](value : T) : Test[T] = {
    testClass.getConstructors.head.newInstance(value, classTag[T]).asInstanceOf[Test[T]]
}