【问题标题】:How get Class[_ <: A]] with lower bound如何获得具有下限的 Class[_ <: A]]
【发布时间】:2020-03-08 20:48:06
【问题描述】:

你好)我在 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

你能帮帮我吗?

【问题讨论】:

    标签: scala reflection


    【解决方案1】:

    问题是runtimeClass的签名:

    def runtimeClass: Class[_]
    

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

    原因是 AnyNothing 等类型。但实际上,ClassTag 在这里没有用,因为您正在执行 ClassTag(&lt;something&gt;).runtimeClass,可以将其简化为 &lt;something&gt;

    所以就投吧:

    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
    }
    

    【讨论】:

    • asSubclass能达到同样的目的吗?
    • 你说得对,当然,我只是不记得了(而且我认为我从未见过它使用过)。
    【解决方案2】:

    像这样试试asSubclass

    def getSubclass[T <: SpecificRecordBase](implicit ct: ClassTag[T]): Class[_ <: SpecificRecordBase] =
      ct.runtimeClass.asSubclass(classOf[SpecificRecordBase])
    
    getSubclass[A]
    getSubclass[B]
    // res0: Class[_ <: SpecificRecordBase] = class A
    // res1: Class[_ <: SpecificRecordBase] = class B
    

    开箱即用的 asSubclass Java implementation 类似于 Alexey 的 Scala 之一

    public <U> Class<? extends U> asSubclass(Class<U> clazz) {
        if (clazz.isAssignableFrom(this))
            return (Class<? extends U>) this;
        else
            throw new ClassCastException(this.toString());
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-11-12
      • 2014-05-23
      • 1970-01-01
      • 2020-11-06
      • 1970-01-01
      • 2022-11-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多