【Kotlin入門】⑤クラス
スポンサードリンク
おはようございます。Shotaです。
今日はKotlin文法の「クラス」について解説します。
クラス
クラスとはオブジェクト指向プログラミングにおいて、オブジェクトの設計図に相当するものです。クラスに基づいて作成されたオブジェクトの実体そのものをインスタンスと呼びます。
クラスに基づいて作成されたオブジェクトは、自身の固有のデータを持ち、自身の動作を記述できます。
クラスはオブジェクト指向プログラミングの基本的な要素です。
クラス宣言
Kotlinでは、クラスをclass
を用いて宣言します。
class Color fun main() { var color = Color() println(color) }
▼実行結果
Color@54bedef2
上のプログラムを実行すると、「クラス名@id」の形で出力されます。
全ての親クラスのデータ型はAny
になります。(Any
とはどのようなデータ型でも扱えるデータ型)そのため、今回説明する文法はすべてAny
の中身に触れます。
クラスの初期化
Kotlinでは、クラスの初期化はコンストラクタ、あるいはイニシャライザを使います。
コンストラクタ
コンストラクタとは、オブジェクト指向プログラミングにおいてクラスをインスタンス化する際に実行される特別なメソッドです。初期化をする時にコンストラクタへ必要な情報を流すことで、新しいオブジェクトを生成できます。
コンストラクタを表現するにはconstructor
を利用しますが、指定しなくても暗黙的に利用されるので省略できます。
ちなみにKotlinのコンストラクタには、プライマリーコンストラクタとセカンダリーコンストラクタの二種類があります。
class User1 constructor() class User2 fun main() { val User1 = User1() val User2 = User2() println(User1) println(User2) }
▼実行結果
User1@8efb846 User2@2a84aee7
コンストラクタの引数は必要に応じて、val
、var
を使えます。もちろん省略しても構いません。
class User(age: Int) class Userval(val age: Int) class Uservar(var age: Int) fun main() { val user = User(age = 20) // user.ageにアクセスできない val userval = Userval(age = 33) // valで指定されているので上書きできない println(userval.age) val uservar = Uservar(age = 33) uservar.age = 10 // varで指定されているので上書きOK println(uservar.age) }
このプログラムの一番上にあるUser
クラスの記述を消してプログラムを実行すると次のようになります。
33 10
プライマリーコンストラクタ
Kotlinのプライマリーコンストラクタの定義は次の通りです。書き方は普通のクラスと同じです。
class User { constructor() { println("Primary Constructor") } } fun main() { val user = User() println(user) }
▼実行結果
Primary Constructor User@54bedef2
セカンダリーコンストラクタ
セカンダリーコンストラクタは最初に定義したプライマリーコンストラクタの下に書きます。
class User { // プライマリーコンストラクタ constructor() { println("Primary Constructor") } // セカンダリーコンストラクタ constructor(age: Int): this() { println("Primary Constructor age=$age") } } fun main() { val user2 = User(age=40) println(user2) }
▼実行結果
Primary Constructor Primary Constructor age=40 User@54bedef2
セカンダリーコンストラクタの処理を実行すると、プライマリーコンストラクタで定義した処理と一緒に実行されます。
イニシャライザ
イニシャライザとは、コンストラクタよりも前に実行される処理でinit
を用いて実行します。更にinit
はブロック宣言を用いることで初期化時に必要な処理内容を記述できます。
イニシャライザとコンストラクタの実行順序は次の通りです。
class User { // イニシャライザ init { println("Initializer") } // プライマリーコンストラクタ constructor() { println("Primary Constructor") } // セカンダリーコンストラクタ constructor(age: Int): this() { println("Primary Constructor age=$age") } } fun main() { val user1 = User() println("user1 = $user1") val user2 = User(age=30) println("user2 = $user2") }
▼実行結果
Initializer Primary Constructor user1 = User@54bedef2 Initializer Primary Constructor Primary Constructor age=30 user2 = User@5caf905d
インスタンスuser1
では、イニシャライザとプライマリーコンストラクタの処理が実行されます。一方で、インスタンスuser2
でセカンダリーコンストラクタのプロパティを指定すると、イニシャライザとプライマリーコンストラクタだけではなくセカンダリーコンストラクタの処理も実行されます。
プロパティ
プロパティとはアクセスされた時にフィールドのように振る舞い、フィールドはクラス内部で状態を保持します。
プロパティの実装はアクセサー(getter
、setter
)を使い、プロパティがアクセスされたときや値を割り当てたい時にアクセサーで定義された内容を実行できます。
また、プロパティはvar
あるいはval
を用いて宣言でき、必ず初期化する必要があります。次の通り、インスタンスからプロパティにアクセスできます。
class Language { val lang = "kotlin" //プロパティの初期化が必要 var version = 1.4 } fun main() { val language = Language() println(language.lang) println(language.version) language.version = 1.6 println(language.version) // varで定義されているので変更OK }
▼実行結果
kotlin 1.4 1.6
プロパティはgetter
あるいはsetter
を自動的に作りますが、カスタマイズしたgetter
やsetter
も定義できます。
var
宣言に対してはget()
とset()
、val
宣言に対してはget()
を利用してカスタマイズできます。
class Language { val lang get() = "kotlin" var version = 1.4 get() { println("Get Value=$field") return field } set(value) { field = value println("Set Value=$field") } } fun main() { val language = Language() println(language.lang) // kotlinと表示 println(language.version) // Get value = 1.4と表示 language.version = 1.6 // Set value = 1.6と表示 println(language.version) // Get value = 1.6と1.6が表示 }
▼実行結果
kotlin Get Value=1.4 1.4 Set Value=1.6 Get Value=1.6 1.6
上のコードを見ると、field
が利用されています。もちろん、setter
だけではなくgetter
でも利用できますが。これはバッキングフィールドと呼ばれる特殊なフィールドでフィールド宣言時に自動的に提供されます。
内部の値はfield
に格納されるので、setter
やgetter
で内部の値を操作したいときはfield
を利用します。
インナークラス
クラスの中にクラスを持つような構造を内部クラスといいます。外部クラスと内部クラスが分離されているので、内部クラスを隠蔽できます。はじめに単純なclass
をネストする構造で挙動を説明します。
下のプログラムでは、Version.Kotlin()
で直接Version
クラスからKotlin
インスタンスを生成できるようになっています。ネストされたクラスは単に外部クラスの名前空間内のクラスとなっています。したがって、内部のクラスからouterVersion
にアクセスできず、また外部クラスからinnerVersion
にアクセスできません。
class Versions { var outerVersion = 1.0 class Kotlin { var innerVersion = 1.6 fun setOuterversion(version: Double) { // outerVersion = version // コンパイルエラー。outerVersionを参照できない。 } } fun setInnerVersion(version: Double) { // innerVersion = version // コンパイルエラー。innerVersionを参照できない。 } } fun main() { println(Versions.Kotlin().innerVersion) }
▼実行結果(コメントアウトされている部分は除外して)
1.6
では、inner class
宣言を用いて内部クラスを定義するとどのように変化するでしょうか?内部クラスからouterVersion
にアクセスできるようになりました。
inner class
宣言で外部クラスから内部クラスへアクセスはできませんが、内部クラスから外部クラスへアクセスできます。
class Versions { var outerVersion = 0.0 inner class Kotlin { var innerVersion = 1.4 fun setOuterVersion(version: Double) { outerVersion = version } } fun setInnerVersion(version: Double) { innerVersion = version // コンパイルエラー。innerVersionを参照できない。 } } fun main() { println(Versions().Kotlin().innerVersion) }
▼実行結果(コメントアウトされている部分は除外)
1.4
このように内部クラスから外部クラスへアクセスできました。
オブジェクト宣言
class
ではなくobject
で宣言すると、インスタンスを一つだけ保持するシングルトンクラスを生成できます。
object Versions { const val KOTLIN = 1.6 const val GRADLE = 6.7 const val JETPACK_COMPOSE = 0.1 fun asMap() = mapOf( "kotlin" to KOTLIN, "gradle" to GRADLE, "jetpackCompose" to JETPACK_COMPOSE ) } fun main() { println(Versions.KOTLIN) println(Versions.asMap()) }
▼実行結果
1.6 {kotlin=1.6, gradle=6.7, jetpackCompose=0.1}
クラス内にオブジェクトを配置する方法として、companion object
宣言があります。
companion object
はシングルトンで作られており、内包されたプロパティや関数はクラスを介して直接アクセスできます。
class Versions { companion object { val KOTLIN = 1.6 val GRADLE = 6.7 val JETPACK_COMPOSE = 0.1 fun asMap() = mapOf( "kotlin" to KOTLIN, "gradle" to GRADLE, "jetpackCompose" to JETPACK_COMPOSE ) } } fun main() { println(Versions.KOTLIN) println(Versions.asMap()) }
▼実行結果
1.6 {kotlin=1.6, gradle=6.7, jetpackCompose=0.1}
抽象クラス宣言
抽象クラスを利用するには、abstract
で宣言する必要があり、関数やプロパティを抽象化できます。
下のプログラムは、Kotlin
実装クラスに対してLanguage
という抽象クラスを継承したサンプルになります。
abstract class Language { abstract val version: Double abstract fun packageName(): String } class Kotlin: Language() { override val version = 1.4 override fun packageName() = "example.kotlin" } fun main() { val kotlin = Kotlin() println(kotlin.version) println(kotlin.packageName()) }
▼実行結果
1.4 example.kotlin
まとめ
今日の記事ではKotlinのクラスについて解説しました。
本記事で解説した内容は次の通りです。
今日の記事はこれで終了です。
【参考】