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

时间:2011-11-21 06:43:43

标签: generics scala manifest

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

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

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

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

我怀疑这种失败是由于API指出,m.erasure的结果类型与T之间没有子类型关系。

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

任何指针?

3 个答案:

答案 0 :(得分:28)

def myClassOf[T:ClassTag] = implicitly[ClassTag[T]].runtimeClass

答案 1 :(得分:14)

您可以将m.erasure的结果投射到Class[T]

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

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

scala> new myclass[String]().something()
res5: Class[String] = class java.lang.String

但是请注意如果我为List[String]使用T之类的实例化类型构造函数会发生什么:

scala> new myclass[List[String]]().something()
res6: Class[List[String]] = class scala.collection.immutable.List

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

修改

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

例如,

Class

这些结果可能会让您感到惊讶和/或导致程序中出现错误。你不应该以这种方式比较类,而应该通过scala> classOf[List[String]] == classOf[List[Int]] res25: Boolean = true scala> classOf[List[String]].isAssignableFrom(classOf[List[Int]]) res26: Boolean = true 来代替并比较它们,因为它们有更多的信息*:

Manifest

据我了解,scala> manifest[List[String]] == manifest[List[Int]] res27: Boolean = false scala> manifest[List[String]] >:> manifest[List[Int]] res28: Boolean = false 用于取代大多数用例的Manifest ...但当然,如果您使用的框架需要Class ,没有太多选择。我认为强制推销Class的结果只是一种“责任承认”,即您使用劣质产品需要您自担风险:)

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

答案 2 :(得分: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]