Scala关于ClassTag 、Manifest、ClassManifest、TypeTag的使用

Scala中ClassTag 、Manifest、ClassManifest、TypeTag是描述运行时类型信息的,由于Scala是运行在JVM之上的,所以首选需要从JVM说起。JVM中的泛型并不会保存泛型的,我们一般在Java开始时候涉及到的泛型都是源码级别的,当我们反编译打开编译之后的class文件会发现并不存在泛型信息。Scala为了在运行时能够获取到泛型信息,就推出了如上关键字。

 

首先先看一个在Java中由于运行期间无法获取泛型信息的例子:

 

 

 
  1. class ArrayDemo<T> {

  2. public T[] arrays = new T[10]; //创建泛型数组不可以,编译不通过

  3.  
  4. public T[] makeArray(int size) {

  5.  
  6. return new T[size];//错误信息还是: 创建泛型数组

  7. }

  8. }


在Scala中同样存在这个例子:

 

 
  1. class ScalaArrayDemo[T] {

  2.  
  3. //Error: cannot find class tag for element type T

  4. def makeTArray(): Array[T] = new Array[T](10)

  5.  
  6. }

 

Scala为了解决这个问题就提出了Manifest、ClassManifest、ClassTag 、TypeTag关键字。

 

Manifest:

 

 
  1. /**

  2. * Created by Daxin on 2017/8/10.

  3. */

  4. class ManifestDemo[T] {

  5.  
  6.  
  7. //Manifest是类型T的显示描述符

  8. def makeTArray[T: Manifest](): Array[T] = new Array[T](10)

  9.  
  10. //等效上面的写法

  11. def makeTArray2()(implicit x: Manifest[T]): Array[T] = new Array[T](10)

  12.  
  13. def makeStringArray(): Array[String] = new Array[String](10)

  14.  
  15. }

  16.  
  17.  
  18. object ManifestDemo extends App {

  19.  
  20. val c = new ManifestDemo[String]

  21.  
  22. c.makeTArray()

  23. c.makeTArray2()

  24.  
  25. }


ClassManifest是Manifest的一个弱化版本,就是保存的类型信息不如Manifest多。不过scala在2.10里却用TypeTag替代了Manifest,用ClassTag替代了ClassManifest,原因是在路径依赖类型中,Manifest存在问题:

 

 
  1. scala> class Foo{class Bar}

  2.  
  3. scala> def m(f: Foo)(b: f.Bar)(implicit ev: Manifest[f.Bar]) = ev

  4.  
  5. scala> val f1 = new Foo;val b1 = new f1.Bar

  6. scala> val f2 = new Foo;val b2 = new f2.Bar

  7.  
  8. scala> val ev1 = m(f1)(b1)

  9. ev1: Manifest[f1.Bar] = Foo@681e731c.type#Foo$Bar

  10.  
  11. scala> val ev2 = m(f2)(b2)

  12. ev2: Manifest[f2.Bar] = Foo@3e50039c.type#Foo$Bar

  13.  
  14. scala> ev1 == ev2 // they should be different, thus the result is wrong

  15. res28: Boolean = true


ev1 不应该等于 ev2 的,因为其依赖路径(外部实例)是不一样的。所以在2.10版本里,使用 TypeTag 替代了 Manifest。而ClassTag是TypeTag的一个弱化版本。

 

 

 
  1. //由于Manifest存在缺陷,所以后面推出了ClassTag

  2. //ClassTag是TypeTag的一个弱化的版本,运行时保存类型信息T。

  3. //更多信息参考文档,文档写的非常清楚

  4. class ClassTagDemo[T] {

  5. def mkArray[T: ClassTag](elems: T*) = Array[T](elems: _*)

  6.  
  7. def mkArray2(elems: T*)(implicit x: ClassTag[T]) = Array[T](elems: _*)

  8.  
  9. // mkArray: [T](elems: T*)(implicit evidence$1: scala.reflect.ClassTag[T])Array[T]

  10.  
  11. // scala> mkArray(42, 13)

  12. // res0: Array[Int] = Array(42, 13)

  13. //

  14. // scala> mkArray("Japan","Brazil","Germany")

  15. // res1: Array[String] = Array(Japan, Brazil, Germany)

  16. }

  17.  
  18. object ClassTagDemo extends App {

  19.  
  20. val c = new ClassTagDemo[Int]

  21. c.mkArray(42, 13)

  22. c.mkArray2(42, 13)

  23.  
  24. }


通过参见SparkContext发现大量使用ClassTag保存泛型信息,没有使用TypeTag。所以一般ClassTag就足以满足我们的需要。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值