閱讀1011 返回首頁    go 阿裏雲 go 技術社區[雲棲]


scala的類與類型

scala的類與類型

類和類型

List<String>和List<Int>類型是不一樣的,但是jvm運行時會采用泛型擦除。導致List<String>和List<Int>都是Class<List>.為了得到正確的類型,需要通過反射。

泛型擦除

Java中的泛型基本上都是在編譯器這個層次來實現的。在生成的Java字節碼中是不包含泛型中的類型信息的。使用泛型的時候加上的類型參數,會在編譯器在編譯的時候去掉。這個過程就稱為類型擦除。泛型擦除是為了兼容jdk1.5之前的jvm,在這之前是不支持泛型的。

classOf與getClass方法的差異

scala> class  A
scala> val a = new A

scala> a.getClass
res2: Class[_ <: A] = class A

scala> classOf[A]
res3: Class[A] = class A

上麵顯示了兩者的不同,getClass 方法得到的是 Class[A]的某個子類,而 classOf[A] 得到是正確的 Class[A],但是去比較的話,這兩個類型是equals為true的

classOf和getClass

classOf獲取運行時的類型。classOf[T] 相當於 java中的T.class

   val listClass = classOf[List[_]]
   * // listClass is java.lang.Class[List[_]] = class scala.collection.immutable.List
   val mapIntString = classOf[Map[Int,String]]
   * // mapIntString is java.lang.Class[Map[Int,String]] = interface scala.collection.immutable.Map
   * }}}

而getClass:

scala> class  A
scala> val a = new A

scala> a.getClass
res2: Class[_ <: A] = class A

scala> classOf[A]
res3: Class[A] = class A

上麵顯示了兩者的不同,getClass 方法得到的是 Class[A]的某個子類,而 classOf[A] 得到是正確的 Class[A],但是去比較的話,這兩個類型是equals為true的

scala> a.getClass  == classOf[A]
res13: Boolean = true

這種細微的差別,體現在類型賦值時,因為java裏的 Class[T]是不支持協變的,所以無法把一個 Class[_ < : A] 賦值給一個 Class[A]

scala> val c:Class[A] = a.getClass
<console>:9: error: type mismatch;

類(class)與類型(type)是兩個不一樣的概念
(在java裏因為早期一直使用class表達type,並且現在也延續這樣的習慣);類型(type)比類(class)更”具體”,任何數據都有類型。類是麵向對象係統裏對同一類數據的抽象,在沒有泛型之前,類型係統不存在高階概念,直接與類一一映射,而泛型出現之後,就不在一一映射了。比如定義class List[T] {}, 可以有List[Int] 和 List[String]等具體類型,它們的類是同一個List,但類型則根據不同的構造參數類型而不同。

類型一致的對象它們的類也是一致的,反過來,類一致的,其類型不一定一致。

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

scala> typeOf[List[Int]] == typeOf[List[String]]
res17: Boolean = false

ClassTag

ClassTag[T]保存了被泛型擦除後的原始類型T,提供給運行時的。

scala> def mkArray[T : ClassTag](elems: T*) = Array[T](elems: _*)
mkArray: [T](elems: T*)(implicit evidence$1: scala.reflect.ClassTag[T])Array[T]

TypeTag

TypeTag則保存所有具體的類型

import scala.reflect.runtime.universe._
def paramInfo[T](x: T)(implicit tag: TypeTag[T]): Unit = {
  val targs = tag.tpe match { case TypeRef(_, _, args) => args }
  println(s"type of $x has type arguments $targs")
}
scala> paramInfo(42)
type of 42 has type arguments List()
scala> paramInfo(List(1, 2))
type of List(1, 2) has type arguments List(Int)

可以看到,獲取到的類型是具體的類型,而不是被擦除後的類型List(Any)

Reference

https://hongjiang.info/scala-type-system-classof-and-getclass/
https://hongjiang.info/scala-type-and-class/
https://www.scala-lang.org/files/archive/nightly/docs/library/index.html
https://blog.csdn.net/lonelyroamer/article/details/7868820

最後更新:2017-04-03 05:39:44

  上一篇:go 微星P55-主板是怎樣造出來的
  下一篇:go Validate File Format