読者です 読者をやめる 読者になる 読者になる
無料で使えるシステムトレードフレームワーク「Jiji」 をリリースしました!

・OANDA Trade APIを利用した、オープンソースのシステムトレードフレームワークです。
・自分だけの取引アルゴリズムで、誰でも、いますぐ、かんたんに、自動取引を開始できます。

Class,Abstract Class,Trait,Objectの違いまとめ

Scala

ScalaByExample - Example 6 Classes and Objectsより。ScalaのClassとかTraitの違いについて、わかる範囲でまとめてみます。

ScalaのClassとかTraitの比較表
  Class Abstract Class Trait Object
抽象メソッドを持てるか? × ×
メソッドの実装を書けるか?
インスタンス化が可能か? × × ○(ただしインスタンスは一つだけ)
コンストラクタ引数の指定ができるか? × ×
継承の制約 Class,Abstract Classのうち1つと、複数のTraitを継承できる 同左 同左 同左
比較用:JavaのClassとかInterfaceの比較表

JavaのClassとかInterfaceを同じ表に当てはめるとこんな感じになります。

  Class Abstract Class Interface
抽象メソッドを持てるか? ×
メソッドの実装を書けるか? ×
インスタンス化が可能か? × ×
コンストラクタ引数の指定ができるか? ×
継承の制約 Class,Abstract Classのうち1つと、複数のInterfaceを継承(実装)できる 同左 複数のInterfaceを継承できる
  • Class,Abstract ClassはJavaと同じ。使い道も同じ(たぶん)
  • TraitはInterfaceに近いけど、
    • メソッドの実装を持てる。実装を書かなければinterface的に使える。実装を書けばMixinができる。
    • 継承の制約がだいぶ違う。Javaだとinterfaceはinterfaceを派生することしかできないけど、TraitはClassやAbstract Classからも派生できる。
  • ObjectはScala独自のものだけど、Javaのstaticな定数に近いかな。(定数という意味ではEnum(のインスタンス)にも近いかも)
// ↓この定数がObjectに近い
static Foo FOO = new Foo() {
 void foo() {}
}
この条件だと、任意のクラスを多重継承できるんでは?

Traitの継承制約が思ってたより緩くて意外。この制約だとTraitを挟むことで任意のクラスを多重継承できそう!に見えるんだけど、やっぱりできません。

// クラス
class A {
  def a = "a"
}
class B {
  def b = "b"
}

// クラスを派生するTrait
trait X extends A {}
trait Y extends B {}

// TraitをMixinしたクラス
class Foo extends X with Y {}

これをコンパイルすると、次の通りエラーになります。

ClassSample.scala:12: error: illegal inheritance; superclass A
 is not a subclass of the superclass B
 of the mixin trait Y
class Foo extends X with Y {}
                         ^
one error found

A,Bが派生関係にあって、「extends X with Y」の順で派生していればOK。

// クラス
class A {
  def a = "a"
}
class B extends A {
  def b = "b"
}

// クラスを派生するTrait
trait X extends A {}
trait Y extends B {}

// TraitをMixinしたクラス
class Foo extends Y with X {}

このとき、FooはBの派生クラスという扱いになるらしい。つまり、内部的には、

class Foo extends B with Y with X {}

と補完されており、暗黙的にFooはB派生と見なされる。ここでBがAを継承していればつじつまが合うのでOKだが、継承していなければFooはAかつB派生にはできないのでエラーになる。ということで、Classを継承したTraitは、Traitを継承したクラスが、Traitの親クラスを継承することを強制したい時に使う機能っぽい。