相對於java的類型系統,scala無疑要複雜的多!也正是這複雜多變的類型系統才讓OOP和FP完美的融合在了一塊兒!html
Nothing:java
若是直接在scala-library中搜索Nothing的話是找不到了,只能發現一個Nothing$的類(後面再說Nothing$和Nothing的關係)。要想看到Nothing.scala的源碼須要去github上的scala源碼中查找Nothing源碼 能夠看到在Nothing.scala中只是定義了一個sealed trait:git
package scala /** `Nothing` is - together with [[scala.Null]] - at the bottom of Scala's type hierarchy. * * `Nothing` is a subtype of every other type (including [[scala.Null]]); there exist * ''no instances'' of this type. Although type `Nothing` is uninhabited, it is * nevertheless useful in several ways. For instance, the Scala library defines a value * [[scala.collection.immutable.Nil]] of type `List[Nothing]`. Because lists are covariant in Scala, * this makes [[scala.collection.immutable.Nil]] an instance of `List[T]`, for any element of type `T`. * * Another usage for Nothing is the return type for methods which never return normally. * One example is method error in [[scala.sys]], which always throws an exception. */ sealed trait Nothing
在這裏,Nothing沒有任何實例,其相似於java中的標示性接口(如:Serializable,用來標識該該類能夠進行序列化),只是用來標識一個空類型。根據官方註釋能夠看出來Nothing用來標識no instances類型,該類型是其它全部類型的子類型。官方註釋中給了以下兩個用途:github
一、用來當作Nil的類型List[Nothing]app
case object Nil extends List[Nothing] {...}
Nil表示一個空的list,與list中的元素類型無關,他能夠同時表示List[任意類型]的空集合。也便是Nil能夠同時表示List[Int]類型的空集合和List[String]類型的空集合。那麼考慮一下Nil:List[?],這裏的「?」應該爲何類型呢?也便是「?」應該爲Int、String....全部類型的子類型(List集合爲協變的)。所以這裏引入了Nothing類型做爲全部類型的子類型。這樣Nil:List[Nothing]就能夠完美實現上述需求。less
二、表示非正常類型的返回值類型ide
例如Nil中的兩個方法:函數
override def head: Nothing = throw new NoSuchElementException("head of empty list") override def tail: List[Nothing] = throw new UnsupportedOperationException("tail of empty list")
Nil爲空List,因此調用head和tail應該返回Nothing和List[Nothing]的實例。可是Nothing是沒有實例的,這裏就直接拋出Exception。因此這裏就使用Nothig來表示throw .... 非正常返回的類型。非正常即發生了錯誤沒有返回任何對象,連Unit都沒有,用Nothing類表示確實也挺合適。post
明白了Nothing的表示的含義以及Nothing的應用場景,那麼,Nothing是如何工做的呢?Nothing和Nothing$之間又有什麼關係呢?this
分別對Nothing.scala和Nothing$.scala進行編譯和反編譯:
Nothing.scala
Nothing$.scala
編譯以後的文件名
根據上面的結果來看,Nothing.scala編譯以後是一個接口類型:
public abstract interface Nothing {}
而Nothing$.scala編譯以後是一個抽象類:
public abstract class Nothing$ extends Throwable{}
從這裏看二者沒有任何關係。可是在Nothign$.scala的源碼中有一段註釋:
package scala package runtime /** * Dummy class which exist only to satisfy the JVM. 虛擬類,只存在於JVM中 * It corresponds to `scala.Nothing`. 它對應scala.Nothing * If such type appears in method signatures, it is erased to this one. 若是該Nothing出如今方法簽名中則將會被抹掉,而後替換爲Nothing$ */ sealed abstract class Nothing$ extends Throwable
這裏闡明瞭Nothing$的做用,也便是代碼中若是出現Nothing類型的時候,在load到JVM運行的時候將會把Nothing替換爲Nothing$類型。也即在JVM以外以Nothing的身份進行顯示,在JVM中以Nothing$的身份進行顯示,二者表示同一個含義。
這樣解釋也知足了Nothing能夠當作 throw new XXXXXException("head of empty list")的類型使用的緣由,即: Nothing$ extends Throwable.
Null:
Null.scala的源碼和Nothing.scala的源碼在同一個包中存在着Null.scala源碼 。對比一下二者:
Null有惟一的實例null Nothing沒有任何實例
Null是全部引用類型(AnyRef)的子類型 Nothing是全部類型的子類型 所以=> Nothing是Null 的子類型
除了上面的兩點區別以外,Null和Nothing幾乎一致
Null.scala 源碼:
package scala /** `Null` is - together with [[scala.Nothing]] - at the bottom of the Scala type hierarchy. * * `Null` is a subtype of all reference types; its only instance is the `null` reference. * Since `Null` is not a subtype of value types, `null` is not a member of any such type. For instance, * it is not possible to assign `null` to a variable of type [[scala.Int]]. */ sealed trait Null
註釋中也明確說明Null是全部引用類型的子類型,只有惟一個一個實例null。trait Null 說明其實一個類型,那麼就能夠用該類型定義字段:val myNull:Null=null
那麼註釋中說Null有惟一的一個實例,那麼咱們new一個Null如何呢?
這裏提示Null是一個abstract抽象類,可源碼中定義的Null是一個trait,那麼這裏在運行的時候爲什麼會提示Null is abstract呢?其次在和Nothing$.scala 旁邊一樣存在一個Null$.scala,這個類和Null.scala又有什麼關係呢?
正如你想象的那樣,Null$.scala正是Null在JVM中的另外一種身份。咱們看一下Null$.scala 的源碼:
package scala package runtime /** * Dummy class which exist only to satisfy the JVM. 該類爲虛擬類,只存在JVM * It corresponds to `scala.Null`. 它對應着scala.Null * If such type appears in method signatures, it is erased to this one. 若是Null出如今方法簽名中則用Null$去替換 * A private constructor ensures that Java code can't create subclasses. private構造方法確保不會被建立其它實例 * The only value of type Null$ should be null 惟一個實例及時null */ sealed abstract class Null$ private ()
這裏明確指出Null將會被Null$替換,那麼在運行的時候Null便爲Null$類型!原來上面提示Null is abstract是這個緣由!!咱們再進一步確認一下,查看一下Null$.scala 進行編譯看編譯以後的代碼:
對Null$.scala進行編譯而後反編譯結果:
(注意:在javap查看代碼的時候若是是private 構造參數則不會顯示處理,若是是public則會直接顯示處理,上面沒有顯示private Null$()正說明Null$的構造參數正是private類型的)
到這裏就徹底就明白了,Null在運行期間被替換了Null$.
Unit:
在解釋Unit以前須要分析一下函數的返回值有幾種可能性!
一、正常返回了數據,例如 def demo01():Int=10 def demo02():String="hello"
二、方法發生異常,沒有執行結束,未進行返回操做。例如 def demo02():Nothing=throw new NoSuchElementException("head of empty list")
三、方法返回了一個類型X的實例,該類型X表示 「沒有返回值」的類型。這裏有些繞,要仔細理解「沒有返回值」和「沒有返回值類型」。而這裏的X便是Unit,而返回的那個實例即(),在java中表示未void。例如: def demo03():Unit={println("hello")}
對於1很好理解,返回什麼就接受什麼類型。對於2即是上面說的Nothing類型,沒有進行返回操做;對於3是有返回的,只是返回的內容表示「沒有返回值」的類型。
在源碼中很好的解釋了Unit的做用:
/** `Unit` is a subtype of [[scala.AnyVal]]. There is only one value of type * `Unit`, `()`, and it is not represented by any object in the underlying * runtime system. A method with return type `Unit` is analogous to a Java * method which is declared `void`. */ final abstract class Unit private extends AnyVal { // Provide a more specific return type for Scaladoc override def getClass(): Class[Unit] = ??? }
根據註釋能夠看出,Unit是全部AnyVal 的子類(注意區別Nothing),只有一個惟一的Value(注意這裏是Value依舊是實例/對象)。若是方法的返回值類型爲Unit,則相似於java中void。
在Unit的伴生對象中則揭開了Unit和void的關係:
object Unit extends AnyValCompanion { /** Transform a value type into a boxed reference type. * * @param x the Unit to be boxed * @return a scala.runtime.BoxedUnit offering `x` as its underlying value. */ def box(x: Unit): scala.runtime.BoxedUnit = scala.runtime.BoxedUnit.UNIT /** Transform a boxed type into a value type. Note that this * method is not typesafe: it accepts any Object, but will throw * an exception if the argument is not a scala.runtime.BoxedUnit. * * @param x the scala.runtime.BoxedUnit to be unboxed. * @throws ClassCastException if the argument is not a scala.runtime.BoxedUnit * @return the Unit value () */ def unbox(x: java.lang.Object): Unit = x.asInstanceOf[scala.runtime.BoxedUnit] /** The String representation of the scala.Unit companion object. */ override def toString = "object scala.Unit" }
請注意box()和unbox()方法,該方法是對數值類型進行裝箱和拆箱操做,scala中全部的數值型類型類中都有這兩種方法,主要用來數值型向java 數值的封裝型轉化,例如:int->Integer float->Float
那麼Unit中的box()和unbox()也是進行拆裝箱操做了,咱們看到在Unit的unbox中把java.lang.Object類型轉換爲一個BoxeUnit類型的數據,那麼這個BoxedUnit是什麼類型呢?咱們打開源碼看一下:
package scala.runtime; public final class BoxedUnit implements java.io.Serializable { private static final long serialVersionUID = 8405543498931817370L; public final static BoxedUnit UNIT = new BoxedUnit(); public final static Class<Void> TYPE = java.lang.Void.TYPE; private Object readResolve() { return UNIT; } private BoxedUnit() { } public boolean equals(java.lang.Object other) {return this == other;} public int hashCode() { return 0;} public String toString() {return "()";} }
能夠看到其TYPE值直接指向了java的void: public final static Class<Void> TYPE = java.lang.Void.TYPE;
看來scala只是使用Unit對java中的void進行了包裝,用Unit來表示void的類型,用BoxedUnit的單例對象來表示那個惟一的void,也便是Unit中的「()」。到這裏才明白Unit是沒有任何實例的,它只是起一個類型的做用,而那個「()」也只是BoxedUnit的單例對象toSting的輸出內容而已。
None:
在說None以前須要瞭解Option類型。Option類型是對值進行封裝,根據值是否爲null來返回Some(value)或者None:
def apply[A](x: A): Option[A] = if (x == null) None else Some(x)
Option的apply()方法能夠返回None/Some可知None或Some一定是Option的子類了。看三者的定義:
sealed abstract class Option[+A] extends Product with Serializable {}//注意sealed 關鍵字 //class final case class Some[+A](value: A) extends Option[A] { def isEmpty = false def get = value } //Object case object None extends Option[Nothing] { def isEmpty = true def get = throw new NoSuchElementException("None.get") }
Option[+A]前面有sealed 關鍵字,則Option[+A]的全部子類必須在同一個文件中定義。所以Option只有Some和None兩個子類。注意上面對Some和None的定義,Some是Class,而None是Object。class容易理解,是能夠new實例的,而Object類型在編譯以後構造方法是private,沒法在外部生成實例對象,而其中的方法編譯以後變爲static的靜態方法,能夠經過類名直接調用。另外,在對Object進行編譯的時候會同時生成一個XXXX$.class的文件,該類是一個單例類,內部會構造一個 public static XXXX$ MODULE$; 單例對象。None也一樣如此:
所以咱們平時所使用的None其實就是這個public static scala.None$ MODULE$; 單例對象。在應用層面上咱們只須要知道None就是一個Option[Nothing]類型的對象,調用get()方法將會拋出NoSuchElementException("None.get")異常,其存在的目的是爲了表面java中的NullPointerException()的發生。
null:
null 就很容易理解了和java中的null是同一個null。通常在scala中不直接使用null!
Nil:
看一下源碼:
case object Nil extends List[Nothing] {....}
根據object即可知Nil是一個單例對象,一定存在一個Nil$.class,在解壓的scala-library中找到Nil$.class進行反編譯能夠找到Nil$的單例對象:
能夠看到 class scala.collection.immutable.Nil$ extends scala.collection.immutable.List<scala.runtime.Nothing$> ,說明Nil是List[Nothing]的子類。而在源碼中的方法則直接代表了Nil的性質:一個沒有元素的List集合:
override def isEmpty = true//集合爲空 override def head: Nothing = throw new NoSuchElementException("head of empty list")//拋出NoSuchElementException異常 override def tail: List[Nothing] = throw new UnsupportedOperationException("tail of empty list")//拋出UnsupportedOperationException異常
=========================================
原文連接:scala(一)Nothing、Null、Unit、None 、null 、Nil理解 轉載請註明出處!
=========================================
-----end