Scalaのクラス

参考サイト
Scalaクラスメモ(Hishidama's Scala class Memo)

コンストラクタ

コンストラクタとは、インスタンス化するときの処理をまとめた特別なメソッドです。
インスタンス化とは、クラス(設計図)からインスタンス(組み立てられた実物)を作ることです。

scalaのコンストラクタはクラス内に直接書きます。
以下はnameフィールドとgreetメソッドを定義しています。
フィールドは状態、メソッドは行動を保持し、その2つをメンバーと呼びます。

class Person(str: String) {
  val name = str
  def greet(): Unit = println(s"私の名前は${name}です。")
}

val taro = new Person("太郎")

scala> taro.name
res0: String = 太郎

scala> taro.greet
私の名前は太郎です。

コンストラクタ引数を設定しているのに与えないとエラーとなります。

scala> val hanako = new Person
<console>:12: error: not enough arguments for constructor Person: (name: String)Person.
Unspecified value parameter name.

val name = strはコンストラクタ引数にvalを与えることで省略できます。

class Person(val name: String) {
  def greet(): Unit = println(s"私の名前は${name}です。")
}

val taro = new Person("太郎")

scala> taro.name
res0: String = 太郎

scala> taro.greet
私の名前は太郎です。

valを与えないと非公開フィールドになります。

class Person(name: String) {
  def greet(): Unit = println(s"私の名前は${name}です。")
}

val taro = new Person("太郎")

scala> taro.name
<console>:13: error: value name is not a member of Person

アクセス修飾子

アクセス修飾子をdef, val, varの前に付けることで、非公開メンバーにすることができます。

class Person(name: String) {
  private def greet(): Unit = println(s"私の名前は${name}です。")
}

val taro = new Person("太郎")

scala> taro.greet
<console>:13: error: method greet in class Person cannot be accessed in Person

継承

extendsキーワードを使い継承すると、親クラス(継承したクラス)のメンバーを利用できます。親クラスのメソッドを上書きするときはoverrideキーワードを付与します。

継承したときは、親クラスのコンストラクタ引数もちゃんと指定します。

class Person(name: String) {
  def run(): Unit = println(s"${name}は走った!")
  def greet(): Unit = println(s"私の名前は${name}です。")
}

// Personを継承しているのに、Personのコンストラクタに値を渡していないと・・・
// class Student(name: String, grade: Int) extends Person

// 以下のエラーになります
//  not enough arguments for constructor Person: (name: String)Person.

// extends Person(name)として、値を渡します
class Student(name: String, grade: Int) extends Person(name) {
  override def greet(): Unit = println(s"私の名前は${name}で${grade}年生です。")
}

val s = new Student("yamada", 6)

scala> s.run
yamadaは走った!

scala> s.greet
私の名前はyamadaで6年生です。

親と子クラスに同じ名前の公開フィールドがあると衝突しますので、overrideを付与するか、親クラスに渡す引数名を変更しましょう。

class Person(val name: String) {
  def greet(): Unit = println(s"私の名前は${name}です。")
}

// nameがPersonクラスのnameと被っていると
// class Student(val name: String, val grade: Int) extends Person(name) {
//   override def greet(): Unit = println(s"私の名前は${name}で${grade}年生です。")
// }

// 以下のエラーになります。
// error: overriding value name in class Person of type String;

// それを避けるため、overrideを付与するか

class Student(override val name: String, val grade: Int) extends Person(name) {
  override def greet(): Unit = println(s"私の名前は${name}で${grade}年生です。")
}

// または、引数名を変えましょう。

class Student(val _name: String, val grade: Int) extends Person(_name) {
  override def greet(): Unit = println(s"私の名前は${name}で${grade}年生です。")
}