抽象クラスとトレイト(あるいは複数のトレイト)を同時に継承した際に、それぞれで同じメソッドが存在した場合はどうなるのかな?って思い、気になったので調べてみた。
調べる前はコンパイルエラーになるものだと思っていたのだけど、そうでもなく、後に継承した方が勝ちになる様子。
なので、抽象クラスとトレイトで同じ名前のメソッドを定義・実装していた場合、抽象クラスの前にトレイトを継承定義できないので、トレイトのメソッドが必ず優先されることになる。
ついでに、継承周りのアレコレを見て、理解しておくためにメモメモ。やっぱこうやってわざわざブログに書くと覚える気がする!
ちなみにトレイトについては継承でなくミックスインと言うとのこと。
ソース
ってことで今回、下記の様なソースを書いて検証。
// 抽象クラス abstract class Abstract { println(s"Abstract Constructor") def f01 def f02 = println("Abstract f02") def f03 def f04 = println("Abstract f04") } // トレイト1 trait Trait1 { println("Trait1 Constructor") def f01 def f02 = println("Trait1 f02") def f03 = println("Trait1 f03") def f04 def f05 def f06 = println("Trait1 f06") def f07 def f08 = println("Trait1 f08") } // トレイト2 trait Trait2 { println("Trait2 Constructor") def f05 def f06 = println("Trait2 f06") def f07 = println("Trait2 f07") def f08 } // 実行クラス class Child extends Abstract with Trait1 with Trait2 { println("Child Constructor") // super.f01 // 定義するとコンパイルエラーになる(Abstract、Trait1ともに実装なし) super.f02 // Trait1に定義したf02が呼び出される(Abstract、Trait1ともに実装あり) super.f03 // Trait1に定義したf03が呼び出される super.f04 // Abstractに定義したf04が呼び出される // super.f05 // 定義するとコンパイルエラーになる(Trait1、Trait2ともに実装なし) super.f06 // Trait2に定義したf06が呼び出される(Trait1、Trait2ともに実装あり) super.f07 // Trait2に定義したf07が呼び出される super.f08 // Trait1に定義したf08が呼び出される def f01 = println("Child f01") // Abstract、Trait1ともに実装が無いので、overrideではなく実装 override def f02 = println("Child f02") // 要 override override def f03 = println("Child f03") // 要 override override def f04 = println("Child f04") // 要 override def f05 = println("Child f05") // Abstract、Trait1ともに実装が無いので、overrideではなく実装 override def f06 = println("Child f06") // 要 override override def f07 = println("Child f07") // 要 override override def f08 = println("Child f08") // 要 override } // 実行用 object Main extends App { // インスタンス生成により実行 new Child }
実行結果
そして結果。
Abstract Constructor Trait1 Constructor Trait2 Constructor Child Constructor Trait1 f02 Trait1 f03 Abstract f04 Trait2 f06 Trait2 f07 Trait1 f08
当たり前っちゃ当たり前の結果になるんだけど、下記の通りの結果。