プログラマに優しい現実指向JVM言語 Kotlin入門

第4回 クラスを学ぶ

この記事を読むのに必要な時間:およそ 5 分

前回はKotlinの基本文法と関数について解説しました。今回はKotlinにおけるオブジェクト指向プログラミングを実現するクラスと,それを取り巻く機能を紹介します。

クラスの定義とインスタンスの生成

KotlinはJavaと同じくクラスベースのオブジェクト指向言語です。すなわち,まずクラスがあり,それからインスタンスを生成し利用するというスタイルです。

メンバをいっさい持たないクラスの定義例をリスト1に示します。Javaと同様classキーワードが必要です。

リスト1 最小のクラス定義

class MyClass

このMyClassクラスをインスタンス化してみましょうリスト2)⁠

リスト2 クラスのインスタンス化

val obj = MyClass()
println(obj) // => MyClass@604e9f7f

MyClass()によりMyClassクラスのインスタンスが生成されます。newのようなキーワードは必要ありません(Kotlinではnewはキーワードではありません)⁠リスト2ではMyClassクラスのインスタンスを生成して,その参照を変数objに代入しています。それをprintlnするとクラス名とハッシュコードが出力されます。

メソッド

メソッドを持ったクラスを定義しましょう。リスト3Greeterクラスはgreetメソッドを持っています。このようにクラスはメンバを波括弧{}で括る必要があります。メソッドはfunキーワードを使って関数のように記述します。

リスト3 メソッドを持ったクラス

class Greeter {
  fun greet() {
    println("Hello!")
  }
}

リスト4のようにGreeterクラスをインスタンス化して,そのインスタンスに対してgreetメソッドを呼び出します。

リスト4 メソッドの呼び出し class User {

val greeter = Greeter()
greeter.greet() // => Hello!

プロパティ

クラスはプロパティを持つことができます。プロパティとは,平たく言えばJavaにおけるフィールドとそのアクセサ(setterやgetter)が一緒になったものと説明できます。

リスト5Userクラスはidnameという名前のプロパティを持っています。インスタン化してプロパティに値を設定したり取得したりしてみましょう。

リスト5 プロパティを持ったクラス

var id: Long = 0
  var name: String = ""
  }

リスト6の2行目ではnameプロパティに値を設定しています。そして3行目でnameプロパティとidプロパティの値を取得しています。Javaにおけるフィールドに直接アクセスしているように見えますが,実際には(デフォルトで生成された)setterやgetterを介してアクセスしています。

リスト6 プロパティの使い方

val taro = User()
taro.name = "Taro"
println("${taro.name}(${taro.id})") // = > Taro(0)

setterやgetterをカスタマイズしたい場合はリスト7のように,関数に似た記法を用いて自由に処理を盛り込めます。誌面の都合上,詳細は割愛させていただきます。公式ドキュメントをご覧ください。

リスト7 setterとgetterのカスタマイズ

class User {
  var id: Long = 0

  var name: String = ""
  // 値が設定されるときにログを出力する
  set(value) {
    println("set: $value")
    $name = value
  }
  // 値が取得されるときにログを出力する
  get() {
    println("get")
    return $name
  }
}

コンストラクタ引数

クラス名の後に続けてコンストラクタの引数リストを宣言できます。ここで受け取った引数でもってプロパティを初期化することができます。

リスト8はもっとシンプルになります。

リスト8 コンストラクタ引数でプロパティ初期化

class User(id: Long, name: String) {
  val id = id
  val name = name
}

リスト9のようにコンストラクタ引数の名前の前にvalvarを付けることでプロパティの定義も兼ねることができ,スッキリした見た目にできます。

リスト9 コンストラクタ引数でプロパティ定義

class User(val id: Long, val name: String)

継承

Javaやそのほかの言語にもあるように,クラスは別のクラスを継承できます。継承すると継承元クラス(スーパクラス)の型のサブ型となり,またスーパクラスのメンバを自クラスのもののように扱うことができるようになります。

このことをシンプルな例から確認しましょう。まずスーパクラスとなるFooクラスを定義しますリスト10)⁠

リスト10 openなクラス

open class Foo {
  fun foo() {
  println("Foo")
  }
}

Fooクラスは,コンストラクタ引数,プロパティを持たず,fooメソッドを持ったクラスです。さらに注目すべきポイントはopenという修飾子が付いていることです。Kotlinでは,クラスが継承可能であることをopen修飾子を付けて明示する必要があります。逆を言えばopenが付いていないクラスは継承できません注1)⁠

リスト11Fooを継承したBarクラスを定義します。

リスト11 Fooのサブクラス

class Bar: Foo() {
  fun bar() {
    println("Bar")
  }
}

クラス名の後に続けてコロン:)⁠スーパクラスのコンストラクタ呼び出しを記述します。今回,Fooクラスはコンストラクタ引数がないのでFoo()となっています。

ではBarのインスタンスからスーパクラスで定義したメソッドを呼び出せるか確かめてみましょうリスト12)⁠そしてBarは,Fooのサブ型なのでval foo: Foo = barは有効なコードです。

リスト12 スーパクラスのメソッド呼び出し

val bar: Bar = Bar()
bar.foo() // => Foo
bar.bar() // => Bar
注1)
厳しい制約のように思えるかもしれませんが『Effective Java 第2版』の項目17に則った設計思想です。

著者プロフィール

長澤太郎(ながさわたろう)

早稲田大学情報理工学科を2012年に卒業。同年入社したメーカー系SIerを経て,2013年にエムスリー株式会社へ入社。以来,世界の医療を変革するためソフトウェアエンジニアとして従事。

日本Kotlinユーザグループ代表,日本Javaユーザグループ幹事を務める。国内初となるKotlin入門書「Kotlinスタートブック」(リックテレコム)の著者。

ビールとディズニーが大好き。

コメント

コメントの記入