Scala - 从泛型类型中获取类对象

dhg*_*dhg 19 generics scala manifest

是否可以纯粹从泛型参数创建一个Class对象?例如:

class myclass[T] { 
  def something(): Class[_ <: T] = 
    classOf[T] //this doesn't work
}
Run Code Online (Sandbox Code Playgroud)

由于该类型将在运行时被删除,因此这似乎是清单的工作,但我还没有找到一个演示此特定用法的示例.我尝试了以下方法,但它也不起作用:

class myclass[T] { 
  def something()(implicit m: Manifest[T]): Class[_ <: T] = 
    m.erasure //this doesn't work
}
Run Code Online (Sandbox Code Playgroud)

我怀疑这个失败是由于,正如API指出的那样,m.erasure结果的类型和结果之间没有子类型关系T.

编辑:我不是真的对类型T是什么感兴趣,我只需要一个类型的对象Class[_ <: T]传递给hadoop框架中的方法.

有什么指针吗?

Ali*_*ehi 29

def myClassOf[T:ClassTag] = implicitly[ClassTag[T]].runtimeClass
Run Code Online (Sandbox Code Playgroud)

  • 这个答案是为Scala 2.10及更高版本准备的,因为Manifest已被弃用. (7认同)

Tom*_*ett 15

您可以将结果m.erasure转换为Class[T]:

class myclass[T] { 
    def something()(implicit m: Manifest[T]): Class[T] = 
        m.erasure.asInstanceOf[Class[T]]
}
Run Code Online (Sandbox Code Playgroud)

这适用于基本(非泛型)类型:

scala> new myclass[String]().something()
res5: Class[String] = class java.lang.String
Run Code Online (Sandbox Code Playgroud)

但要注意,如果我用一个实例化的类型构造一样会发生什么List[String]T:

scala> new myclass[List[String]]().something()
res6: Class[List[String]] = class scala.collection.immutable.List
Run Code Online (Sandbox Code Playgroud)

由于擦除,Class给定类型构造函数的所有可能实例化只有一个对象.

编辑

我不确定为什么Manifest[T].erasure返回Class[_]而不是Class[T],但如果我不得不推测,我会说这是为了阻止你使用Class允许你比较两个类的相等或子类型关系的方法,因为这些方法会给你错误的Class使用实例化的泛型类型参数化时的答案.

例如,

scala> classOf[List[String]] == classOf[List[Int]]
res25: Boolean = true

scala> classOf[List[String]].isAssignableFrom(classOf[List[Int]])
res26: Boolean = true
Run Code Online (Sandbox Code Playgroud)

这些结果可能会让您感到惊讶和/或导致程序中出现错误.你不应该以这种方式比较类,而应该通过传递Manifests来代替它们,因为它们有更多的信息*:

scala> manifest[List[String]] == manifest[List[Int]]
res27: Boolean = false

scala> manifest[List[String]] >:> manifest[List[Int]]
res28: Boolean = false
Run Code Online (Sandbox Code Playgroud)

根据我的理解,Manifests意味着取代Class大多数用例...但当然,如果你使用的框架需要一个Class,那就没有多少选择了.我认为强制推销结果erasure只是一种"承担责任",你使用的是劣质产品,风险自负:)

*请注意,正如Manifest文档所述,这些明显的比较运算符"应仅被视为近似值,因为类型一致性的许多方面尚未在清单中充分表示."


mis*_*tor 5

.erasure为您提供要擦除的类型。如果需要完整的类型信息,则应返回Manifest

scala> class MyClass[A] {
     |   def stuff(implicit m: Manifest[A]): Class[_] = m.erasure
     | }
defined class MyClass

scala> new MyClass[Int].stuff
res551: java.lang.Class[_] = int

scala> new MyClass[List[Int]].stuff
res552: java.lang.Class[_] = class scala.collection.immutable.List

scala> class MyClass[A] {
     |   def stuff(implicit m: Manifest[A]): Manifest[A] = m
     | }
defined class MyClass

scala> new MyClass[Int].stuff
res553: Manifest[Int] = Int

scala> new MyClass[List[Int]].stuff
res554: Manifest[List[Int]] = scala.collection.immutable.List[Int]
Run Code Online (Sandbox Code Playgroud)