Android Studio 3.0を使い、最近話題のプログラミング言語「Kotlin」の特徴を解説する連載。今回は、Kotlinプログラミングでも重要な位置付けとなる「クラス」関連の機能について扱います。
Android Studioを使い、Kotlin言語の特徴を解説する本連載「Android Studioで始めるKotlin入門」。これまでの連載では、Kotlinの基本的な構文からNull安全に関する機能までを説明しました。
連載第4回の今回から、Kotlinのクラス関連機能について扱っていきます。クラス関連の機能はKotlinプログラミングでも重要な位置付けとなるため、今回から次の第5回まで連続で扱っていく予定です。これまでの機能と同様、クラス関連機能にもJavaとの共通点と相違点の両方があります。基本的な概念を共通としながらも、Android開発を含めた実際の開発現場で便利な機能がサポートされています。
Kotlinのクラスに関する基本的な概念はJavaと似通っています。リスト1は2つのメソッドを持つクラスの定義と、その使用例です。
//基本的なクラス定義の例 class Car(){ //メソッド定義 fun start(){ println("発進") } fun stop(){ println("停止") } } …… //newではなく、クラス名をメソッドのように使ってインスタンスを作る val car = Car() //メソッド呼び出しなどはJavaと同様 car.start() //→「発進」が出力される car.stop() //→「停止」が出力される
クラス定義はJavaと同じく「class」キーワードを使って定義します。メソッド定義は関数と同様に「fun」キーワードを使用します。
注意点はクラスをインスタンス化するときです。Javaのような「new」キーワードは存在せず、クラス名をメソッドのように呼び出すことでインスタンスを生成します。メソッド呼び出しについてはJavaと同様です。
さらに注意が必要なのは、Kotlinのクラスにはstaticメソッド、つまりインスタンス生成なしでクラスに対して呼び出せるクラスメソッドが存在しないことです。これはJavaやC#とは大きく異なる点です。代替として、Kotlinにはクラス外に定義できる関数があるので、staticメソッドの代わりに関数の使用が推奨されています。
Javaのクラスには値を保持するためのフィールドがありますが、Kotlinではプロパティという概念を使います。プロパティはフィールドと似ていますが、「フィールドが単純にクラスの中に変数を持っているだけ」なのに対し、「プロパティは値の取得、設定の際に任意のロジックを記述できる」という点が異なります。
リスト2はプロパティを持つクラスの例です。普通の変数宣言のように「var」を使った書き換え可能なプロパティや、「val」を使った書き換え不可能なプロパティを定義できます。また、推論可能な初期値を設定することで、データ型を省略することもできます。
//プロパティを持つクラス定義の例 class Counter(){ //書き換え可能なプロパティの定義 var counter: Int = 0 //書き換え不可能なプロパティ。ここではデータ型を省略して推論させている val maxValue = 10 fun countUp(){ //プロパティの値に1を加算 counter += 1 } fun print(){ println("現在のカウント値: ${counter}") } } …… //プロパティの使用例 val counter = Counter() counter.print() //「現在のカウント値: 0」が出力される counter.countUp() counter.countUp() counter.print() //「現在のカウント値: 2」が出力される
さて、これだけだとJavaのフィールドと同じに思えるかもしれませんが、前述の通りKotlinのプロパティは、取得、設定の際にリスト3のように「getter」「setter」と呼ばれるロジックを書くことができます。これらを「アクセサ」と呼びます。ここでは、時計クラスを作成し、0時から何秒経過したかを取得、設定する「pastSeconds」というプロパティを定義しています。
//時計クラスの定義 class Clock(){ //時・分・秒のプロパティ var hour: Int = 0 var minute: Int = 0 var second: Int = 0 //00:00:00から何秒経過したかを取得・設定するプロパティ var pastSeconds: Int get(){ //getキーワードでgetter(取得の際のロジック)を定義 return ((hour * 60) + minute) * 60 + second } set(value){ //setキーワードでsetter(設定の際のロジック)を定義 //セットする値はvalueという変数に入っている hour = value / 3600 minute = (value % 3600) / 60 second = value % 60 } fun print(){ //現在のプロパティの値を表示 //pastSecondsプロパティはgetterロジックを実行 println("${hour}時${minute}分${second}秒, 0時から${pastSeconds}秒経過") } } …… val clock = Clock() //普通にプロパティに値を設定。ここはフィールドと同様 clock.hour = 1 clock.minute = 10 clock.second = 5 clock.print() // 「1時10分5秒, 0時から4205秒経過」が出力される //pastSecondsプロパティに値を設定。setterロジックを実行 clock.pastSeconds = 4101 clock.print() //「1時8分21秒, 0時から4101秒経過」が出力される
Javaではクラスのフィールドを直接外部に公開せずにprivateフィールドとした上で、「getXXX」「setXXX」といった名前を持つpublicメソッドを使って値を入出力するカプセル化が一般的です。Kotlinのプロパティは、このカプセル化が言語レベルでサポートされていると考えるといいでしょう。アクセサを使ったプロパティとgetter/setterによるカプセル化は原理的にほぼ同じ仕組みですが、書きやすさ、読みやすさはプロパティの方が格段に上といえるでしょう。
リスト4は、あるプロパティの値に1を加算するコードを、プロパティとJavaのgetter/setterを使って書いたサンプルです。
//Kotlinでhourプロパティに1を加える clock.hour = clock.hour + 1 //Javaでgetter/setterを使って同様の処理を書く clock.setHour(clock.getHour() + 1);
getter/setterを使うよりも、プロパティを使った方が、より直感的な書き方ができますね(この辺りは、C#や他のプロパティをサポートした言語のプログラマーであればよく理解できることでしょう)。
Copyright © ITmedia, Inc. All Rights Reserved.