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



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

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)

我在某处设置了带有 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,有两种参数类型:

  • 类 java.lang.Object
  • interface scala.reflect.ClassTag

好。如何提供类标签?这里有什么问题?有没有更好的方法,解决方法?

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

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]]
}

最新更新