Kotlinのクラス定義とかプライマリコンストラクタとプロパティの初期化のやり方を整理する。
環境情報
kotlin 1.3.72
Kotlin のクラス定義のおさらい
class Hoge( // ここがプライマリコンストラクタ val moge: String val boke: String ) { // 波括弧で囲まれている箇所がクラス本体 init { // ここが初期化ブロック } constructor(moge: String) : this(moge, "ぼけ") // ここがセカンダリコンストラクタ }
よくみるこのプライマリコンストラクタでプロパティを初期化する形、実は省略形。
class Hoge( val moge: String val boke: String )
「constructor」と付いた形が本来のプライマリコンストラクタの形。
// 「constructor」 は可視性修飾子やアノテーションがなければ省略できる // つまりこの場合は省略できる class Hoge constructor( val moge: String val boke: String ) { } // 可視性修飾子付きのこっちは省略できない class Hoge private constructor( val moge: String val boke: String ) { }
Kotlin のコンストラクタ呼び出し
class Hoge() // クラス定義 Hoge() // クラス名の後に丸括弧を付けてコンストラクタ呼び出し→インスタンス作成
インスタンス生成と共にプロパティを初期化する
初期化の仕方など
プライマリコンストラクタで初期化する。
引数にvalやvarなどを付けるだけ。
「インスタンス生成」と「プロパティ初期化」を同時に出来る。
class Hoge( val moge: String, val boke: String ) val hoge = Hoge("もげ", "ぼけ") println(hoge.moge) // もげ println(hoge.boke) // ほげ
プライマリコンストラクタの引数をすべてデフォルト値ありにすると、コンパイラが勝手に引数なしコンストラクタ(デフォルトコンストラクタ)を作ってくれる。
// 引数なしのコンストラクタの呼び出し Hoge()
そのため、何もしなくても引数なしで以下のように呼べる。
class Hoge( val moge: String = "もげ", // デフォルト引数 val boke: String = "ぼけ" // デフォルト引数 ) val hoge = Hoge() println(hoge.moge) // もげ println(hoge.boke) // ほげ
インスタンス生成時にプロパティは初期化しない
プライマリコンストラクタで引数だけを取る
プライマリコンストラクタ内で引数は取るが初期化はしない場合。
インスタンスは生成するがプロパティは初期化していない
class Hoge( moge: String, // valなし boke: String // valなし ) val hoge = Hoge("もげ", "ぼけ") // インスタンス生成はコンストラクタを呼び出している形になる。 println(hoge.moge) // エラー println(hoge.boke) // エラー
プライマリコンストラクタ内でvalを付けてないので初期化しないとプロパティは呼べない。
Parameter 'moge' is never used Parameter 'boke' is never used Unresolved reference: moge Unresolved reference: boke
引数を取ってクラス本体で初期化する
プライマリコンストラクタで初期化しないことも、もちろんできる。
class Hoge( moge: String, boke: String ) { // クラス本体で初期化している val moge = moge val boke = boke } val hoge = Hoge("もげ", "ぼけ") println(hoge.moge) // もげ println(hoge.boke) // ぼげ
クラス本体でvalを宣言しているが、単純な初期化処理の場合なら下記の方がいいです。
内部的な違いは無いですが、簡潔に書ける方を選びます。
class Hoge( val moge: String, val boke: String )
ただ、初期化時に固定値を入れたい場合はコンストラクタでプロパティをセットする意味は薄いです。
コンストラクタで設定せずクラス定義に置いたほうがコンストラクタの役割が明確です。
// コンストラクタで固定値セットすることが増えると引数がどんどん増えていく。 class Hoge( val momo: String, val moge: Boolean = true, val hoge: List<String> = emptyList() ) { } // なので固定値はクラス定義でセットする class Hoge( val momo: String ) { val moge: Boolean = true, val hoge: List<String> = emptyList() }
参考
Kotlin – コンストラクタ / 覚えたら書く
https://blog.y-yuki.net/entry/2019/05/25/093000
コメント