Scalaにも抽象クラスがあります。Javaと同じようにabstract修飾子をつけます。
abstract class Elemen { def contents: Array[String] }
contentsメソッドは宣言していますが、定義はありません。
定義が無い場合、Javaと違いメソッドの明示的にabstractをつけなくても抽象メンバーとなります。
パラメータ無しメソッド
次のElementのheightとwidthは括弧がありません。括弧をつけないメソッドはパラメータ無しメソッド(oarameterless methods)と呼びます。
空の括弧をつけてパラメータ無しメソッドも定義することもでき、こちらは空括弧メソッド(empty-paren methods)と呼びます。
abstract class Element { def contents: Array[String] def height: Int = contents.length def width: Int = if (height == 0) 0 else contents(0).length }
パラメータが無くミュータブルな状態へのアクセスがオブジェクトのフィールドの読み出しのみの場合はパラメータ無しメソッドを使い、そうで無い場合は空括弧メソッドを使うという習慣があります。
また、defをvalに帰ればメソッドでは無くフィールドとして実装できます。
abstract class Element { def contents: Array[String] val height: Int = contents.length val width: Int = if (height == 0) 0 else contents(0).length }
API利用者からは同じように使えますが、もちろんメソッドとフィールドどちらの実装方法でも動作に違いが無いようにしなければなりません。
Javaとの互換性
Javaではメソッドの実行とフィールドの参照は記法が区別されています。list.size()やarray.lengthなどです。
ScalaはJavaのクラスで同じようにアクセスできるよう、パラメータ無しメソッドと空括弧メソッドはどちらの記法でも呼び出せるようになっています。
scala> "hoge".toString res2: String = hoge scala> "hoge".toString() res3: String = hoge
Scalaの関数呼び出しでは、すべての空括弧は省略できます。しかし、プロパティの参照以上の意味を持つ場合は空括弧をつける方が良いとなっています。
"Hello".length // 副作用が無いので括弧無し println() // 副作用があるので括弧あり
クラスの拡張
抽象クラスであるElementクラスを継承し、ArrayElementクラスを作ります。
Javaと同じようにextends節を記述します。
class ArrayElement(conts: Array[String]) extends Element { def contents: Array[String] = conts }
extends節を省略すると、そのクラスは暗黙的にscala.AnyRefを継承します。
Javaで言うところのObjectを継承するというのと同じです。
メソッドとフィールドのオーバーライド
Scalaではフィールドとメソッドを統一的に扱っているため、スーパークラスのフィールドをサブクラスのパラメータ無しメソッドでオーバーライドしたり、その逆もできます。
そのため、Javaと違い同じ名前でフィールドとパラメータ無しメソッドを定義できません。メソッドがパラメータを取る場合はOKです。
// 同じ名前でもパラメータを取ればOK
scala> class WontCompile { | var f = 0 | def f(i: Int) = 1 | } defined class WontCompile scala> var a = new WontCompile() a: WontCompile = WontCompile@1ae8bcbc scala> a.f res8: Int = 0 scala> a.f(1) res9: Int = 1
パラメータフィールドの定義
Scalaでは、コンストラクタのパラメータをフィールドにすることができます。
先ほどのArrayElementは次のように書けます。パラメータにvalをつけるだけです。
class ArrayElement( val contents: Array[String] ) extends Element
No Comments