Kotlinのクラスやプロパティについて

採用はこちら

Kotlinにおけるクラスプロパティは、Javaと似ているようで思想が大きく異なります。

特に「プロパティは単なるフィールドではない」「不変性を前提に設計する」という点を理解できるかどうかで、Kotlinコードの質は大きく変わります。

本記事では、仕様的に正確で、実務でも安全に使える知識に絞って解説します。

目次

Kotlinのクラス定義の基本

class User

これだけでクラス定義として成立します。

Kotlinでは、Javaのように必ずしも {} を書く必要はありません。

プライマリコンストラクタ(Kotlinの核)

Kotlinでは、クラス定義とコンストラクタが一体化しています。

class User(name: String, age: Int)

ここで注意すべき点は以下です。

  • nameageただのコンストラクタ引数
  • この時点では クラスのプロパティではない

プロパティとは何か

プロパティの正確な定義

Kotlinのプロパティは、

  • 必ず getter(varの場合は setter も)を持つ
  • バッキングフィールドは必要な場合にのみ生成される

という特徴があります。

プライマリコンストラクタでのプロパティ定義

class User(val name: String, var age: Int)

これは内部的に次のような構造になります。

class User(name: String, age: Int) {
    val name: String = name
    var age: Int = age
}

val と var の違い

キーワード意味再代入
val読み取り専用プロパティ
var可変プロパティ
val name = "Taro"
var age = 20

Kotlinでは 原則 val を使い、どうしても状態変更が必要な場合のみ var を使います。

クラスボディとメンバー関数

class User(val name: String, var age: Int) {

    fun introduce() {
        println("私は$name、年齢は$age歳です")
    }
}
  • this は通常不要
  • 文字列テンプレートが自然に使える

初期化処理(init ブロック)

class User(val name: String, var age: Int) {

    init {
        require(age >= 0) { "年齢は0以上である必要があります" }
    }
}
  • プライマリコンストラクタ実行直後に呼ばれる
  • require が失敗すると IllegalArgumentException が投げられる
  • 入力値バリデーションに最適

セカンダリコンストラクタ

class User(val name: String, var age: Int) {

    constructor(name: String) : this(name, 0)
}

ルール

  • プライマリコンストラクタが存在する場合
    • セカンダリコンストラクタは必ず this(...) に委譲する
  • プライマリがないクラスでは super(...) に委譲する

実務では、ほとんどの場合プライマリコンストラクタだけで十分です。

カスタム getter / setter

フィールドを持たない計算プロパティ

class User(val firstName: String, val lastName: String) {

    val fullName: String
        get() = "$firstName $lastName"
}
  • バッキングフィールドは生成されない
  • 常に最新の値が計算される

setter を持つプロパティ

class User(age: Int) {

    var age: Int = age
        set(value) {
            require(value >= 0)
            field = value
        }
}
  • field はバッキングフィールドを指す特別な識別子
  • getter / setter 内でのみ使用可能

アクセス修飾子(可視性)

修飾子意味
publicどこからでもアクセス可能(デフォルト)
privateクラス内のみ
protected継承先を含む
internal同一モジュール(Gradle / Maven のコンパイル単位)内
class User(
    val name: String,
    private val password: String
)

data class

data class User(
    val name: String,
    val age: Int
)

自動生成されるもの

  • equals() / hashCode()
  • toString()
  • copy()
  • componentN()

copy の活用例

val user1 = User("Taro", 20)
val user2 = user1.copy(age = 21)

data class の制約(重要)

  • プライマリコンストラクタ引数が最低1つ必要
  • 主に val / var のプロパティが対象
  • DTO・状態管理に最適

遅延初期化

lateinit(var専用)

lateinit var user: User
  • non-null 型のみ使用可能
  • プリミティブ型(Int 等)は不可
  • 初期化前アクセスで UninitializedPropertyAccessException

lazy(val専用)

val user: User by lazy {
    User("Taro", 20)
}
  • 初回アクセス時に初期化
  • デフォルトはスレッドセーフ
  • 重い処理の遅延生成に有効

Kotlinらしいクラス設計の指針

  • 状態はできるだけ val にする
  • setter を乱用しない
  • 不変オブジェクト + copy を活用する
  • データは data class、振る舞いは関数で表現する

Java的アンチパターン

Java風

class User {
    private var name: String? = null

    fun getName(): String? = name
}

Kotlinらしい書き方

class User(val name: String)

実務での使い分けまとめ

用途推奨
API / DB / DTOdata class
ドメインモデルclass + val中心
状態管理data class + copy
設定値object

以上、Kotlinのクラスやプロパティについてでした。

最後までお読みいただき、ありがとうございました。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次