java裏 jvm在運行時採用類型擦拭的做法,類型已經不能單純的用class來區分了,比如 List 和 List 的class 都是 Class,然而兩者類型(type)卻是不同的。
在Scala裏,類型系統又比java複雜很多,它自己提供了一個scala.reflect.runtime.universe.Type
在scala用typeOf獲取類型信息:
scala> import scala.reflect.runtime.universe._
scala> class A
scala> typeOf[A]
res44: reflect.runtime.universe.Type = A
同樣scala裏獲取類(Class)信息也很便捷:
scala> classOf[A]
另外,因爲 java 的Object裏提供了getClass方法,對於scala 對象來說,也可以用
scala> val a = new A
scala> a.getClass
res53: Class[_ <: A] = class A
注意,typeOf 和 classOf 方法接收的都是類型符號,並不是對象實例
scala> object O
scala> classOf[O] // 這裏O是一個單例對象,是一個實例
:14: error: not found: type O
對於實例,要獲取他的 Class 信息,只有通過 getClass 方法
scala> O.getClass
res60: Class[_ <: O.type] = class O$
注意到了,上面的 單例對象O 對應的class是 O$ ,你通過 :javap O 也能看到這個單例反編譯後是一個名爲O$的 java class
看上面的返回類型裏 用:O.type 表示其類型;實際上 .type之前的都可以看做是一種類型路徑,每個實例都可以通過.type方式表達它的單例類型
再舉一個例子:
scala> class A { class B } // 嵌套類
scala> val a1 = new A
scala> val a2 = new A
scala> val b1 = new a1.B
scala> val b2 = new a2.B
對於內部類B的實例,它們的class都是相同的: A$B(表示B是A的內部類)
scala> b1.getClass
res8: Class[_ <: a1.B] = class A$B
scala> b1.getClass == b2.getClass
res7: Boolean = true
而它們的類型卻是不同的:
scala> typeOf[a1.B] == typeOf[a2.B]
res10: Boolean = false
這是因爲內部類型依賴外部實例(路徑依賴類型),外部實例不同,它們也不同。
但還可以對這種類型再抽象
scala> typeOf[a1.B] <:< typeOf[A#B]
res11: Boolean = true
scala> typeOf[a2.B] <:< typeOf[A#B]
res12: Boolean = true
這裏A#B涉及到類型投影的概念,如前所講。
簡單的說,類(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
在jvm裏,類的實例都是引用形式,而類型沒有這個約束,基礎類型int,byte,char等就是非引用的。類型比類更“具體”,更“細”一些。
作者:scandly
鏈接:https://www.jianshu.com/p/6bb03a0a771c
來源:簡書
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。