Kotlinにおけるクラスとプロパティは、Javaと似ているようで思想が大きく異なります。
特に「プロパティは単なるフィールドではない」「不変性を前提に設計する」という点を理解できるかどうかで、Kotlinコードの質は大きく変わります。
本記事では、仕様的に正確で、実務でも安全に使える知識に絞って解説します。
目次
Kotlinのクラス定義の基本
class User
これだけでクラス定義として成立します。
Kotlinでは、Javaのように必ずしも {} を書く必要はありません。
プライマリコンストラクタ(Kotlinの核)
Kotlinでは、クラス定義とコンストラクタが一体化しています。
class User(name: String, age: Int)
ここで注意すべき点は以下です。
nameとageは ただのコンストラクタ引数- この時点では クラスのプロパティではない
プロパティとは何か
プロパティの正確な定義
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 / DTO | data class |
| ドメインモデル | class + val中心 |
| 状態管理 | data class + copy |
| 設定値 | object |
以上、Kotlinのクラスやプロパティについてでした。
最後までお読みいただき、ありがとうございました。










