Scala Class etc.

Classes

  • 一個(gè)源文件可包含多個(gè)類,每個(gè)類默認(rèn)都是 public
  • 類字段必須初始化,編譯后默認(rèn)是 private,自動(dòng)生成 public 的 getter/setter ;Person 示例
    • private 字段,生成 private 的 getter/setter
    • val 字段,只生成 getter
    • private[this] 字段,不生成 getter/setter
    • 自定義 getter/setter,foo 和 foo_=
  • 類方法默認(rèn)都是 public
  • 方法調(diào)用規(guī)約:訪問(wèn)器調(diào)用可省略括號(hào),修改器調(diào)用加上括號(hào)
  • 為字段加上 @bean.BeanProperty 注解可生成符合 JavaBean 規(guī)范的 get/set 方法(加上默認(rèn)的兩個(gè)方法,共四個(gè)方法)
  • 構(gòu)造器:1 個(gè)主構(gòu)造器,任意個(gè)輔構(gòu)造器
    • 全部都叫 this,只是參數(shù)不同
    • 輔構(gòu)造器必須調(diào)用主構(gòu)造器或之前定義的輔構(gòu)造器
    • 主構(gòu)造器與類定義密不可分,參數(shù)直接定義在類名后
    • 主構(gòu)造器會(huì)立即執(zhí)行類定義中的所有語(yǔ)句
    • 主構(gòu)造器中的參數(shù)被方法使用到,則對(duì)應(yīng)的參數(shù)等價(jià)于 private[this] val 字段
  • 內(nèi)部類
    • 路徑依賴,不同于 Java 內(nèi)部類,同一類 A 的不同實(shí)例(a1, a2)構(gòu)建的內(nèi)部類 Inner,其類型是不同的,a1.Inner != a2.Inner
    • 解決路徑依賴
      • 類型投射,Outer#Inner
      • 將內(nèi)部類放到伴生對(duì)象 object 中
    • self => 自身類型,區(qū)分調(diào)用的內(nèi)部類和外部類的字段、方法等

Objects

  • 用于單例及工具類方法
    • object 構(gòu)造器只在第一次被調(diào)用時(shí)執(zhí)行
  • 可繼承一個(gè) class 或多個(gè) trait
    • 可用于全局默認(rèn)對(duì)象
  • 不可提供構(gòu)造器參數(shù)
  • 伴生對(duì)象
    • 與類名稱一致
    • 類與伴生對(duì)象可互相訪問(wèn)私有資源,但區(qū)分作用域,如 Accounts.newUniqueNumber() 而不是 newUniqueNumber()
    • 類與伴生對(duì)象必須在同一個(gè)源文件中
  • 伴生對(duì)象中的 apply 方法
    • 調(diào)用方式 Object(arg1, ..., argN), 返回伴生類的實(shí)例,如 Array(1,2,3)
    • 省略 new 關(guān)鍵字,在嵌套表達(dá)式中很方便
  • 應(yīng)用對(duì)象
    • extends App
    • 不需要 main 方法直接執(zhí)行構(gòu)造器內(nèi)的代碼
  • scala 默認(rèn)無(wú)枚舉類型
    • 使用 Enumeration 幫助類實(shí)現(xiàn)
    • 枚舉類型為 Enumeration.Value(ID, name) 內(nèi)部類, ID 依次累加, 默認(rèn) 0 開(kāi)始;name 默認(rèn)是字段名

Traits

  • 替代 Java 中的接口
  • 可以有抽象的和具體的方法
    • trait 中未實(shí)現(xiàn)的方法默認(rèn)是抽象的 (abstract)
  • 類可以實(shí)現(xiàn)多個(gè) trait,從最后一個(gè)開(kāi)始調(diào)用
    • 使用 extends 關(guān)鍵字實(shí)現(xiàn)
    • 覆蓋抽象方法時(shí)不需要 override 關(guān)鍵字
    • 有多個(gè) trait 則對(duì)其他的 trait 使用 with 關(guān)鍵字
  • 所有的 Java 接口都可以被當(dāng)做 trait 使用
  • 對(duì)象也可以添加多個(gè) trait,從最后一個(gè)開(kāi)始調(diào)用
  • 多個(gè) trait 的情況下,super.someMethod 會(huì)根據(jù)從右向左的順序調(diào)用下一個(gè) trait 的方法
    • 具體調(diào)用依賴于使用時(shí)的順序,相比傳統(tǒng)的繼承更靈活
    • 在多個(gè) mix-in 的情況下,如果父trait存在抽象方法,則子trait需使用 abstract override 關(guān)鍵字,否則 super.someMethod 無(wú)法編譯
  • 有初始值的字段/具體字段,都會(huì)被添加到子類中
  • 無(wú)初始值的字段/抽象字段,在非抽象子類中,需要進(jìn)行初始化
  • trait 也有構(gòu)造器
    • 不可以有構(gòu)造參數(shù),且只有一個(gè)構(gòu)造器
    • 由定義體中的初始化字段和其他語(yǔ)句構(gòu)成
    • 構(gòu)造順序:父類 > 各trait從左向右,有父 trait 的先構(gòu)造,共享的父 trait 只構(gòu)造一次 > 子類
    • 考慮到構(gòu)造順序,如果子類中使用抽象字段,則可使用提前定義(early definition,會(huì)在構(gòu)造器之前執(zhí)行)的語(yǔ)法講改字段初始化
      • 提前定義語(yǔ)句塊中只能使用字段定義語(yǔ)句,不可使用其他語(yǔ)句
  • trait 可繼承類,混入該 trait 的類都是被繼承類的子類,子類如果有繼承其他的類也必須是被繼承類的子類
  • 與自身類型(self type)比較
    • trait 不繼承類,直接在 body 內(nèi)定義 this: Type =>,則混入的類必須是該 Type 類型的/子類型的
    • 也可使用結(jié)構(gòu)類型(structural type),this: { def log(msg: String) } => ,則混入的類必須包含結(jié)構(gòu)類型中定義的方法
  • trait 最終會(huì)翻譯成類和接口

Packages and Imports

  • package 包名和文件路徑并不一定對(duì)應(yīng)
  • java.lang, scala, Predef 始終默認(rèn)會(huì)導(dǎo)入
  • 與 Java 不同,包路徑并不是絕對(duì)的,如 collection.mutable 實(shí)際是 scala.collection.mutable
  • package a.b.cpackage a { package b { package c {}}} 不同
    • package apackage b 中定義的資源可在帶括號(hào)的包聲明中訪問(wèn),但 package a.b.c 無(wú)法訪問(wèn)
  • 包對(duì)象
    • package 由于 JVM 的限制不能直接聲明函數(shù)或變量
    • 不同于 package, package object 可定義工具函數(shù)或常量
  • 可見(jiàn)性控制,通過(guò) private[package.name] 限制資源的可見(jiàn)性
  • import
    • 導(dǎo)入包后可使用相對(duì)路徑訪問(wèn)類等,如 collection.mutable
    • 導(dǎo)入所有資源 import collection.mutable._
    • 可在任意位置進(jìn)行導(dǎo)入操作
    • selector
      • 選擇性的導(dǎo)入一部分成員,import java.awt.{Color, Font}
      • 為導(dǎo)入成員取別名:import java.util.{HashMap => JavaMap}
      • 隱藏成員: import java.util.{HashMap => _, _} // 避免產(chǎn)生混淆
    • 隱式導(dǎo)入,默認(rèn)導(dǎo)入三個(gè) java.lang, scalaPredef
      • 后面導(dǎo)入的可將前面的成員覆蓋,避免沖突
      • 導(dǎo)入 scala 相關(guān)的包可省略 scala 路徑

Inheritance

fragile base class 基類被繼承之后,修改基類可能會(huì)對(duì)子類造成無(wú)法預(yù)期的影響

  • 繼承類,與 Java 一樣使用 extends 關(guān)鍵字

    • final 類不能被繼承, final 字段、方法不能被覆蓋
  • 覆蓋非抽象方法,必須使用 override 關(guān)鍵字

  • 抽象方法

    • 無(wú)方法體的方法,可以省略 abstract 關(guān)鍵字;子類覆蓋時(shí)也可以省略 override
  • 抽象字段

    • 無(wú)初始值的字段,可省略 abstract 關(guān)鍵字,子類覆蓋式也可省略 override
  • 調(diào)用父類方法,使用 super 關(guān)鍵字

  • 類型檢查和轉(zhuǎn)換, isInstanceOf, asInstanceOf;獲取類型, classOf

    • 模式匹配通常是個(gè)更好的類型檢查方式
  • protected 不同于 Java,受保護(hù)成員在包內(nèi)不可見(jiàn)

  • 輔助構(gòu)造器不可直接調(diào)用超類構(gòu)造器

    • 可在定義類時(shí)直接在 extends 時(shí)調(diào)用超類構(gòu)造器并傳遞參數(shù)
    • 繼承 Java 類時(shí)主構(gòu)造器必須調(diào)用超類的構(gòu)造器
  • 覆蓋字段

    • def 只能覆蓋 def
    • val 只能覆蓋 無(wú)參數(shù)的 def
    • var 只能覆蓋 抽象的 var
  • 繼承層級(jí)

    file
    • Any 定義了 asInstanceOf, isInstanceOf,判斷相等,hash值等方法
    • AnyRef 是除基礎(chǔ)類型外所有類的父類,等價(jià)于 java.lang.Object
      • 提供方法 wait, notify/notifyAll,synchronized
    • AnyVal 不包含任何方法,只是個(gè)值類型的標(biāo)記
    • 所有 Scala 類都實(shí)現(xiàn)了 ScalaObject 這個(gè)標(biāo)記接口,該接口無(wú)任何方法
    • Null 的唯一實(shí)例 null,可分配給引用類型,但不可分配給值類型(Int 不可為 null)
    • Nothing 無(wú)實(shí)例,在泛型構(gòu)造時(shí)有用,Nil 類型為 List[Nothing]
    • ??? 方法聲明返回類型為 Nothing, 無(wú)返回值,會(huì)拋出 NotImplementedError,用于預(yù)留未實(shí)現(xiàn)的方法
    • Unit 代表空/void,類型唯一值為 ()
    • 如果方法參數(shù)類型為 AnyAnyRef, 當(dāng)傳遞多個(gè)參數(shù)時(shí),會(huì)被替換為 tuple
  • equalshashCode 判斷對(duì)象相等

    • 可使用模式匹配實(shí)現(xiàn) equals
    • equals 參數(shù)類型為 Any 而不是具體的類型
    • ##hashCode 的安全版本,遇到 null 會(huì)返回 0 而不是拋出異常
  • 值類 Value Class

    • 繼承 AnyVal
    • 主構(gòu)造器只有一個(gè)參數(shù) val,無(wú)構(gòu)造體
    • 無(wú)其他構(gòu)造器和字段
    • 自動(dòng)提供的 equalshashCode 比較實(shí)際值
    • 用于隱式轉(zhuǎn)換
      • 其他用途,如 class a(x: Int, y: Int) 設(shè)計(jì)為 class a(x: X, y: Y) ,定義值類 X, Y 避免混淆參數(shù)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容