Scala繼承體系結(jié)構(gòu)

控制復(fù)雜性是計(jì)算機(jī)編程的本質(zhì)。-- Brian Kernigan

Scala繼承體系結(jié)構(gòu)設(shè)計(jì)非常巧妙,它沒有特殊地對待「基本數(shù)據(jù)類型」,將萬物視為對象鉴吹。此外,Scala在頂層引入Any惩琉,它是所有類的父類豆励;而在底層引入了Nothing,它是所有類的子類瞒渠,整個(gè)系統(tǒng)的設(shè)計(jì)保持一致和完整良蒸。

Scala繼承體系結(jié)構(gòu)

Any

總體上,Scala的對象可分為兩個(gè)類型:

  • 引用類型(Reference Types):繼承自AnyRef
  • 值類型(Value Types):繼承自AnyVal

Any則是AnyVal, AnyRef的父類伍玖。也就是說嫩痰,Any是所有Scala類型的父類,它內(nèi)置于Scala內(nèi)部私沮,由編譯器實(shí)現(xiàn)始赎。

元類

Class<T>的實(shí)例代表了T類型的元數(shù)據(jù);對于每個(gè)T類型仔燕,在JVM運(yùn)行時(shí)有且僅有一個(gè)Class<T>的實(shí)例存在。

Scala里魔招,要獲取T類型的Class<T>實(shí)例晰搀,可以使用classOf的實(shí)用方法。

classOf[String]

其中办斑,classOf定義在Predef之中外恕,由Scala的編譯器實(shí)現(xiàn)。

def classOf[T]: Class[T] = ???

強(qiáng)制轉(zhuǎn)換

Scala并沒有提供強(qiáng)制類型轉(zhuǎn)換的特殊語法乡翅,它們是通過調(diào)用isInstanceOf/asInstanceOf方法實(shí)現(xiàn)鳞疲。

if (obj.isInstanceOf[Point])
  val other = obj.asInstanceOf[Point]

它們定義于Any之中,它們都具有一個(gè)類型參數(shù)蠕蚜。

class Any {
  final def isInstanceOf[T]: Boolean = ??? 
  final def asInstanceOf[T]: T = ??? 
}

相等性

Scala使用==/!=比較對象間的邏輯相等性尚洽,而使用eq/ne比較對象間的物理相等性。其中靶累,Any中的==/!=方法使用equals實(shí)現(xiàn)腺毫,并處理了null值比較的情況癣疟。而Any中定義的equals默認(rèn)使用eq比較對象間的物理相等性。也就是說潮酒,如果一個(gè)類未重寫equals方法睛挚,==/!=方法比較對象間的物理相等性。

class Any {
  final def !=(that: Any): Boolean = !(this == that)

  final def ==(that: Any): Boolean =
    if (null eq this) null eq that
    else this equals that

  def equals(that: Any): Boolean = this eq that
}

AnyRef

AnyRef是所有「引用類型」的根類急黎,它等價(jià)于Object扎狱。引用類型要么引用new構(gòu)造的實(shí)例,要么引用null值勃教。

val s: String = null

對象一致性

AnyRef中定義了eq/ne委乌,用于比較對象間的物理相等性。其中荣回,

  • 對于非nullx: AnyRef, x eq nullnull eq x都返回false遭贸;
  • 但是,對于null eq null則返回true心软。
class AnyRef {
  final def ne(that: AnyRef): Boolean = !(this eq that)

  final def eq(that: AnyRef): Boolean = 
    (this, that) match {
      case (null, null) => true
      case (null, _) => false
      case (_, null) => false
      case _ => this same that
  }
  
  // same為編譯器內(nèi)部實(shí)現(xiàn)的壕吹,比較兩個(gè)引用類型的物理相等性
  private def same(that: AnyRef): Boolean = ???
}

Null

Null類型為所有引用類型的子類,其擁有唯一的實(shí)例:null删铃。

package scala

abstract final class Null private extends AnyRef

AnyVal

AnyVal是所有「值類型」的根類耳贬,包括Unit, Bolean, Char, Byte, Short, Int, Long, Float, Double

值類型的實(shí)例猎唁,由編譯器將其映射為原生的基本數(shù)據(jù)類型咒劲,存取效率相當(dāng)高效。但是诫隅,值類型不能使用new構(gòu)造實(shí)例腐魂,也不能持有null值,而應(yīng)該使用「字面值」直接初始化逐纬。

val MAX_NUM: Int = null  // Error

Unit

Unit類型是一個(gè)特殊的值類型蛔屹,它等價(jià)于Java中的void。它擁有唯一的實(shí)例:()豁生,即0個(gè)元素的元組兔毒。

classOf[Unit] // Class[Unit] = void
().getClass   // Class[Unit] = void

classTag[Unit] // scala.reflect.ClassTag[Unit] = Unit
classTag[Unit].runtimeClass // Class[_] = void
過程

返回值類型為Unit的函數(shù)常常稱為「過程」。例如甸箱,Runnable中的run方法就是一個(gè)典型的過程育叁。

trait Runnable {
  def run(): Unit
}

按照慣例,run有可能產(chǎn)生副作用芍殖,為此run顯式地聲明了()豪嗽。

區(qū)分Int, RichInt, Integer

探秘Int

Scala是一門純的面向?qū)ο蟮某绦蛟O(shè)計(jì)語言,它沒有特殊地對待原生的基本數(shù)據(jù)類型,例如int, short, long, char等昵骤。

1 + 2

它實(shí)際上是一個(gè)函數(shù)調(diào)用過程树碱,等價(jià)于

1.+(2)

事實(shí)上,+方法定義在Int類中变秦。

final abstract class Int private extends AnyVal {
  def +(x: Int): Int = ???
  ...
}

為了提升效率成榜,Int將映射為JVM中的int

探秘RichInt

求取110的和蹦玫,可以如此實(shí)現(xiàn)赎婚。

(1 to 10).sum

它等價(jià)于:

1.to(10).sum

但是,Int中并沒有定義to方法樱溉,但1 to 10為什么能夠工作呢挣输?事實(shí)上,在Predef中定義了IntRichInt的隱式轉(zhuǎn)換福贞。

object Predef {
  implicit def intWrapper(x: Int) = new scala.runtime.RichInt(x)
  ...
}

RichInt中剛好定義了一個(gè)to方法撩嚼,它創(chuàng)建了一個(gè)Range.Inclusive類型的實(shí)例。

package scala.runtime

class RichInt {
  def to(end: Int): Range.Inclusive = Range.inclusive(self, end)
  ...
}

RichInt是一個(gè)Int的富包裝類型挖帘。這樣的設(shè)計(jì)機(jī)制完丽,不僅保持了Int的高效,而且也保證了RichInt良好的可擴(kuò)展性拇舀。

探秘Integer

IntegerInt的包裝器逻族,它的實(shí)例分配于堆中。對于Scala骄崩,自動(dòng)裝箱和自動(dòng)拆箱是通過隱式轉(zhuǎn)換完成的聘鳞。或者說要拂,自動(dòng)裝箱和自動(dòng)拆箱僅僅是隱式轉(zhuǎn)換的一個(gè)應(yīng)用場景而已抠璃。

object Predef {
  ...
  implicit def int2Integer(x: Int) = Integer.valueOf(x)
  implicit def Integer2int(x: Integer): Int = x.intValue
}

仿真Boolean

為了加深理解值類型的工作原理,這里自制仿真實(shí)現(xiàn)了一個(gè)Boolean宇弛,其行為等價(jià)于標(biāo)準(zhǔn)庫的Boolean實(shí)現(xiàn)鸡典;但是,此處的Boolean實(shí)現(xiàn)采用了函數(shù)式的設(shè)計(jì)思維枪芒。

函數(shù)式結(jié)構(gòu)

Boolean是一個(gè)典型的函數(shù)式的數(shù)據(jù)結(jié)構(gòu),truefalseBoolean的兩個(gè)字面值谁尸。其中舅踪,eval相當(dāng)于if-else表達(dá)式。

sealed trait Boolean {
  def eval[T](t: => T, e: => T): T
}

object true extends Boolean {
  def eval[T](t: => T, e: => T): T = t
}

object false extends Boolean {
  def eval[T](t: => T, e: => T): T = e
}
短路求值

&&&之間的差異在于前者擁有「短路求值」的特性良蛮,而后者沒有抽碌;

sealed trait Boolean {
  def eval[T](t: => T, e: => T): T
    
  def &&(x: => Boolean): Boolean = eval(x, false)
  def ||(x: => Boolean): Boolean = eval(true, x)
  def unary_! : Boolean = eval(false, true)
  
  def &(x: Boolean): Boolean = eval(x, false)
  def |(x: Boolean): Boolean = eval(true, x)
  def ^(x: Boolean): Boolean = eval(false, True)
}
相等性

對于兩個(gè)Boolean實(shí)例,也可以通過eval實(shí)現(xiàn)==/!=的比較邏輯。

sealed trait Boolean {
  ...
  def eval[T](t: => T, e: => T): T

  def ==(x: Boolean): Boolean = eval(x, !x)
  def !=(x: Boolean): Boolean = eval(!x, x)
}

Nothing

Nothing是一個(gè)特殊的類型货徙,它處在繼承層次的最底部左权,它是所有類的子類。雖然Nothing沒有任何實(shí)例存在痴颊,但它在Scala的類型系統(tǒng)中扮演了重要的角色赏迟。

package scala

final abstract class Nothing extends Throwable
空類型

Nil繼承自List[Nothing],且為唯一的單鍵對象蠢棱;因?yàn)?code>List[+A]是協(xié)變的锌杀,所有對于任意的類型AList[Nothing]都是List[A]的子類泻仙。

sealed abstract class List[+A]

final case class ::[A](head: A, tail: List[A]) extends List[A]
final case object Nil extends List[Nothing]
表示異常

Nothing繼承自Throwable糕再,它表示程序的異常終止。例如玉转,Predef中定義的???占位方法突想,其返回值類型就是聲明為Nothing

object Predef {
  def ??? : Nothing = throw new NotImplementedError
}

在實(shí)施TDD實(shí)踐過程中究抓,為了快速編譯通過猾担,可以使用???表示占位實(shí)現(xiàn)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末漩蟆,一起剝皮案震驚了整個(gè)濱河市垒探,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌怠李,老刑警劉巖圾叼,帶你破解...
    沈念sama閱讀 219,110評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異捺癞,居然都是意外死亡夷蚊,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評論 3 395
  • 文/潘曉璐 我一進(jìn)店門髓介,熙熙樓的掌柜王于貴愁眉苦臉地迎上來惕鼓,“玉大人,你說我怎么就攤上這事唐础∠淦纾” “怎么了?”我有些...
    開封第一講書人閱讀 165,474評論 0 356
  • 文/不壞的土叔 我叫張陵一膨,是天一觀的道長呀邢。 經(jīng)常有香客問我,道長豹绪,這世上最難降的妖魔是什么价淌? 我笑而不...
    開封第一講書人閱讀 58,881評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上蝉衣,老公的妹妹穿的比我還像新娘括尸。我一直安慰自己,他們只是感情好病毡,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,902評論 6 392
  • 文/花漫 我一把揭開白布濒翻。 她就那樣靜靜地躺著,像睡著了一般剪验。 火紅的嫁衣襯著肌膚如雪肴焊。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,698評論 1 305
  • 那天功戚,我揣著相機(jī)與錄音娶眷,去河邊找鬼。 笑死啸臀,一個(gè)胖子當(dāng)著我的面吹牛届宠,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播乘粒,決...
    沈念sama閱讀 40,418評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼豌注,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了灯萍?” 一聲冷哼從身側(cè)響起轧铁,我...
    開封第一講書人閱讀 39,332評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎旦棉,沒想到半個(gè)月后齿风,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,796評論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡绑洛,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,968評論 3 337
  • 正文 我和宋清朗相戀三年救斑,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片真屯。...
    茶點(diǎn)故事閱讀 40,110評論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡脸候,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出绑蔫,到底是詐尸還是另有隱情运沦,我是刑警寧澤,帶...
    沈念sama閱讀 35,792評論 5 346
  • 正文 年R本政府宣布配深,位于F島的核電站茶袒,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏凉馆。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,455評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望澜共。 院中可真熱鬧向叉,春花似錦、人聲如沸嗦董。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽京革。三九已至奇唤,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間匹摇,已是汗流浹背咬扇。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留廊勃,地道東北人懈贺。 一個(gè)月前我還...
    沈念sama閱讀 48,348評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像坡垫,于是被迫代替她去往敵國和親梭灿。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,047評論 2 355

推薦閱讀更多精彩內(nèi)容