object
用途
- ユーティリティメソッド、グローバルなプロパティ値の置き場(equivalent of java static)
- 同名クラスのオブジェクトのファクトリメソッド
class SampleSuper(a: Int)
class Sample(b: Int) extends SampleSuper(b)
object SampleSuper {
def apply(c: Int): SampleSuper = new Sample(c)
}
object Sample {
def apply(c: Int): SampleSuper = new Sample(c)
}
- new クラス名による直接的なオブジェクト生成よりも、実装の詳細を隠蔽できる(インターフェースのみ公開)
- サブクラスのインスタンスを返却することもできる
コンパニオンオブジェクト
- クラスと同じファイル内に、同じ名前で定義されたオブジェクト(シングルトン)のこと
trait
抽象メンバーの上書き
trait TraitA {
val name: String
def printName: String = println(name)
}
class ClassA(val name: String) extends TraitA
トレイとをミックスインしたクラスのコンストラクタで、抽象メンバー name をオーバーライドしている。
object ObjectA {
val a2 = new TraitA { val name = "tsuchiya" }
}
name を上書きするような実装を与えてもよい
菱形継承問題
- override指定なしのメソッド定義衝突はコンパイルエラー
初期化順の要注意
trait A {
val foo: String
}
// トレイトの初期化順序
trait B extends A {
val bar: String = foo + "World"
}
class ClassB extends B {
val foo = "Hello"
def printBar: Unit = println(bar)
}
(new ClassB).printBar // nullWorld
// 初期化順の回避1 遅延評価
trait C extends A {
lazy val bar: String = foo + "World"
}
class ClassC extends C {
val foo = "Hello"
def printBar: Unit = println(bar)
}
(new ClassC).printBar // HelloWorld
// 初期化順の回避2 関数化
trait D extends A {
def bar: String = foo + "World"
}
class ClassD extends D {
val foo = "Hello"
def printBar: Unit = println(bar)
}
(new ClassD).printBar // HelloWorld
// 初期化順の回避3 事前定義(Early Definitions)
trait E extends A {
val bar: String = foo + "World"
}
class ClassE extends {
val foo = "Hello"
} with E {
def printBar: Unit = println(bar)
}
(new ClassE).printBar // HelloWorld
- トレイトの初期化問題は継承されるトレイト側で解決したほうが良いことが多い
型パラメータ(type parameter)
- クラスが受け取ることのできるパラメータ
- 命名規則としては、A.B..の順が多い
共変(covariant)
- 何も指定しない場合、非変(invariant)になる
- 配列は Java では共変だが、Scala では非変