首页 > 解决方案 > 如何获得具有下限的 Class[_ <: A]]

问题描述

你好)我在Java中有一个抽象类和几个具体类

abstract class SpecificRecordBase {}
class A extends SpecificRecordBase 
class B extends SpecificRecordBase
....

我也有一张 Scala 地图。我想把键字符串和值作为一个类在方法中使用它:

def test(m: Map[String, Class[_ <: SpecificRecordBase]]):Unit = ???

我试图 ClassTag(ClassLoader.getSystemClassLoader.loadClass(stringClassName)).runtimeClass 但出现错误。我也尝试创建方法并使用它

  def getClass[T <: SpecificRecordBase](ct: ClassTag[T]): Class[T] = ct.runtimeClass

And also have an error
 Error:(10, 73) type mismatch;
 found   : Class[_$1] where type _$1
 required: Class[T]
  def getClass[T <: SpecificRecordBase](ct: ClassTag[T]): Class[T] = ct.runtimeClass

请问你能帮帮我吗?

标签: scalareflection

解决方案


问题是签名runtimeClass

def runtimeClass: Class[_]

表示类型 U 的类,T 将被擦除到。请注意,T 和 U 之间没有子类型关系。

原因是 , 等类型AnyNothing但实际上,ClassTag在这里没有用,因为您正在做的事情ClassTag(<something>).runtimeClass可以简化为<something>.

所以只需投射它:

ClassLoader.getSystemClassLoader.loadClass(stringClassName).asInstanceOf[Class[_ <: SpecificRecordBase]]

(编辑:正如马里奥·加利奇指出的那样,这应该是

ClassLoader.getSystemClassLoader.loadClass(stringClassName).asSubclass(classOf[SpecificRecordBase])

下面应用了类似的更改。)

甚至更简单

Class.forName(stringClassName).asSubclass(classOf[SpecificRecordBase])

如果您不确定是否会获得 的子类型SpecificRecordBase,可以对其进行测试:

val cls = Class.forName(stringClassName)
Try { cls.asSubclass(classOf[SpecificRecordBase]) } match {
  case Success(cls1) =>
    // handle a subclass
  case Failure(_) =>
    // handle a non-subclass
}

或者没有异常处理

val cls = Class.forName(stringClassName)
if (classOf[SpecificRecordBase].isAssignableFrom(cls)) {
  val cls1 = cls.asInstanceOf[Class[_ <: SpecificRecordBase]]
  // handle a subclass
} else {
  // handle a non-subclass
}

推荐阅读