Classes 一個源文件可包含多個類,每個類預設都是 public 類欄位必須初始化,編譯後預設是 private,自動生成 public 的 getter/setter ; "Person 示例" 欄位,生成 private 的 getter/setter 欄位,只生成 getter 欄位,不生 ...
Classes
- 一個源文件可包含多個類,每個類預設都是 public
- 類欄位必須初始化,編譯後預設是 private,自動生成 public 的 getter/setter ;Person 示例
private
欄位,生成 private 的 getter/setterval
欄位,只生成 getterprivate[this]
欄位,不生成 getter/setter- 自定義 getter/setter,foo 和 foo_=
- 類方法預設都是 public
- 方法調用規約:訪問器調用可省略括弧,修改器調用加上括弧
- 為欄位加上
@bean.BeanProperty
註解可生成符合 JavaBean 規範的 get/set 方法(加上預設的兩個方法,共四個方法) - 構造器:1 個主構造器,任意個輔構造器
- 全部都叫
this
,只是參數不同 - 輔構造器必須調用主構造器或之前定義的輔構造器
- 主構造器與類定義密不可分,參數直接定義在類名後
- 主構造器會立即執行類定義中的所有語句
- 主構造器中的參數被方法使用到,則對應的參數等價於
private[this] val
欄位
- 全部都叫
- 內部類
- 路徑依賴,不同於 Java 內部類,同一類 A 的不同實例(a1, a2)構建的內部類 Inner,其類型是不同的,a1.Inner != a2.Inner
- 解決路徑依賴
- 類型投射,Outer#Inner
- 將內部類放到伴生對象 object 中
self =>
自身類型,區分調用的內部類和外部類的欄位、方法等
Objects
- 用於單例及工具類方法
- object 構造器只在第一次被調用時執行
- 可繼承一個
class
或多個trait
- 可用於全局預設對象
- 不可提供構造器參數
- 伴生對象
- 與類名稱一致
- 類與伴生對象可互相訪問私有資源,但區分作用域,如
Accounts.newUniqueNumber()
而不是newUniqueNumber()
- 類與伴生對象必須在同一個源文件中
- 伴生對象中的
apply
方法- 調用方式
Object(arg1, ..., argN)
, 返回伴生類的實例,如Array(1,2,3)
- 省略
new
關鍵字,在嵌套表達式中很方便
- 調用方式
- 應用對象
extends App
- 不需要 main 方法直接執行構造器內的代碼
- scala 預設無枚舉類型
- 使用
Enumeration
幫助類實現 - 枚舉類型為
Enumeration.Value(ID, name)
內部類, ID 依次累加, 預設 0 開始;name 預設是欄位名
- 使用
Traits
- 替代 Java 中的介面
- 可以有抽象的和具體的方法
- 在
trait
中未實現的方法預設是抽象的 (abstract)
- 在
- 類可以實現多個
trait
,從最後一個開始調用- 使用
extends
關鍵字實現 - 覆蓋抽象方法時不需要
override
關鍵字 - 有多個
trait
則對其他的trait
使用with
關鍵字
- 使用
- 所有的 Java 介面都可以被當做
trait
使用 - 對象也可以添加多個
trait
,從最後一個開始調用 - 多個
trait
的情況下,super.someMethod
會根據從右向左的順序調用下一個trait
的方法- 具體調用依賴於使用時的順序,相比傳統的繼承更靈活
- 在多個 mix-in 的情況下,如果父
trait
存在抽象方法,則子trait
需使用abstract override
關鍵字,否則super.someMethod
無法編譯
- 有初始值的欄位/具體欄位,都會被添加到子類中
- 無初始值的欄位/抽象欄位,在非抽象子類中,需要進行初始化
trait
也有構造器- 不可以有構造參數,且只有一個構造器
- 由定義體中的初始化欄位和其他語句構成
- 構造順序:父類 > 各
trait
從左向右,有父trait
的先構造,共用的父trait
只構造一次 > 子類 - 考慮到構造順序,如果子類中使用抽象欄位,則可使用提前定義(early definition,會在構造器之前執行)的語法講改欄位初始化
- 提前定義語句塊中只能使用欄位定義語句,不可使用其他語句
trait
可繼承類,混入該trait
的類都是被繼承類的子類,子類如果有繼承其他的類也必須是被繼承類的子類- 與自身類型(self type)比較
trait
不繼承類,直接在 body 內定義this: Type =>
,則混入的類必須是該 Type 類型的/子類型的- 也可使用結構類型(structural type),
this: { def log(msg: String) } =>
,則混入的類必須包含結構類型中定義的方法
trait
最終會翻譯成類和介面
Packages and Imports
package
包名和文件路徑並不一定對應java.lang
,scala
,Predef
始終預設會導入- 與 Java 不同,包路徑並不是絕對的,如
collection.mutable
實際是scala.collection.mutable
package a.b.c
與package a { package b { package c {}}}
不同package a
或package b
中定義的資源可在帶括弧的包聲明中訪問,但package a.b.c
無法訪問
- 包對象
- package 由於 JVM 的限制不能直接聲明函數或變數
- 不同於 package, package object 可定義工具函數或常量
- 可見性控制,通過
private[package.name]
限制資源的可見性 import
- 導入包後可使用相對路徑訪問類等,如
collection.mutable
- 導入所有資源
import collection.mutable._
- 可在任意位置進行導入操作
selector
- 選擇性的導入一部分成員,
import java.awt.{Color, Font}
- 為導入成員取別名:
import java.util.{HashMap => JavaMap}
- 隱藏成員:
import java.util.{HashMap => _, _}
// 避免產生混淆
- 選擇性的導入一部分成員,
- 隱式導入,預設導入三個
java.lang
,scala
和Predef
- 後面導入的可將前面的成員覆蓋,避免衝突
- 導入 scala 相關的包可省略
scala
路徑
- 導入包後可使用相對路徑訪問類等,如
Inheritance
fragile base class
基類被繼承之後,修改基類可能會對子類造成無法預期的影響
- 繼承類,與 Java 一樣使用
extends
關鍵字final
類不能被繼承,final
欄位、方法不能被覆蓋
- 覆蓋非抽象方法,必須使用
override
關鍵字 - 抽象方法
- 無方法體的方法,可以省略
abstract
關鍵字;子類覆蓋時也可以省略override
- 無方法體的方法,可以省略
- 抽象欄位
- 無初始值的欄位,可省略
abstract
關鍵字,子類覆蓋式也可省略override
- 無初始值的欄位,可省略
- 調用父類方法,使用
super
關鍵字 - 類型檢查和轉換,
isInstanceOf
,asInstanceOf
;獲取類型,classOf
- 模式匹配通常是個更好的類型檢查方式
protected
不同於 Java,受保護成員在包內不可見- 輔助構造器不可直接調用超類構造器
- 可在定義類時直接在 extends 時調用超類構造器並傳遞參數
- 繼承 Java 類時主構造器必須調用超類的構造器
- 覆蓋欄位
def
只能覆蓋def
val
只能覆蓋 無參數的def
var
只能覆蓋 抽象的var
繼承層級
Any
定義了asInstanceOf
,isInstanceOf
,判斷相等,hash值等方法AnyRef
是除基礎類型外所有類的父類,等價於java.lang.Object
- 提供方法
wait
,notify/notifyAll
,synchronized
- 提供方法
AnyVal
不包含任何方法,只是個值類型的標記- 所有 Scala 類都實現了
ScalaObject
這個標記介面,該介面無任何方法 Null
的唯一實例null
,可分配給引用類型,但不可分配給值類型(Int
不可為null
)Nothing
無實例,在泛型構造時有用,Nil
類型為List[Nothing]
???
方法聲明返回類型為Nothing
, 無返回值,會拋出NotImplementedError
,用於預留未實現的方法Unit
代表空/void
,類型唯一值為()
- 如果方法參數類型為
Any
或AnyRef
, 當傳遞多個參數時,會被替換為tuple
equals
和hashCode
判斷對象相等- 可使用模式匹配實現
equals
equals
參數類型為Any
而不是具體的類型##
是hashCode
的安全版本,遇到null
會返回 0 而不是拋出異常
- 可使用模式匹配實現
- 值類 Value Class
- 繼承
AnyVal
- 主構造器只有一個參數 val,無構造體
- 無其他構造器和欄位
- 自動提供的
equals
和hashCode
比較實際值 - 用於隱式轉換
- 其他用途,如
class a(x: Int, y: Int)
設計為class a(x: X, y: Y)
,定義值類X
,Y
避免混淆參數
- 其他用途,如
- 繼承