class / コンストラクター
| 対応: | Kotlin 1.0(2016) |
|---|
Kotlinのクラスは『class』キーワードで定義します。プライマリコンストラクターはクラスヘッダーに直接書け、初期化処理は『init』ブロックに記述します。セカンダリコンストラクターは『constructor』キーワードを使います。
構文
// プライマリコンストラクター(最も一般的な形式)
class Person(val name: String, var age: Int)
// init ブロックで初期化処理を記述
class User(val name: String, val age: Int) {
init {
require(age >= 0) { "年齢は0以上である必要があります" }
}
}
// セカンダリコンストラクター(constructor キーワード)
class Point {
val x: Double
val y: Double
constructor(x: Double, y: Double) {
this.x = x
this.y = y
}
constructor(value: Double) : this(value, value) // 委譲
}
構文一覧
| 構文 | 概要 |
|---|---|
| class クラス名(val x: 型) | プロパティを持つプライマリコンストラクターです。 |
| init { } | インスタンス生成時に実行される初期化ブロックです。 |
| constructor(引数) { } | セカンダリコンストラクターの定義です。 |
| : this(引数) | 別のコンストラクターに委譲します。 |
| private constructor | コンストラクターをプライベートにします(ファクトリーパターン等)。 |
サンプルコード
sample_class_constructor.kt
// プライマリコンストラクターとプロパティ定義
class Person(
val name: String,
var age: Int,
val email: String = "" // デフォルト引数
) {
// init ブロックはコンストラクター実行後に呼ばれる
init {
require(name.isNotBlank()) { "名前は空にできません" }
require(age >= 0) { "年齢は0以上である必要があります" }
println("Person インスタンス生成: $name (${age}歳)")
}
// プロパティの計算
val greeting: String
get() = "こんにちは、${name}です!"
}
// セカンダリコンストラクターの例
class Rectangle(val width: Double, val height: Double) {
val area: Double = width * height
// 正方形用のセカンダリコンストラクター
constructor(side: Double) : this(side, side)
}
// private コンストラクター(ファクトリーパターン)
class Database private constructor(val url: String) {
companion object {
fun create(url: String): Database {
println("データベース接続: $url")
return Database(url)
}
}
}
fun main() {
// プライマリコンストラクターでインスタンス生成
val p1 = Person("user_1", 20, "user_1@wp-p.info")
println(p1.greeting)
// デフォルト引数を使う
val p2 = Person("user_2", 20)
println("user_2 のメール: '${p2.email}'") // 空文字
// 名前付き引数でコンストラクターを呼び出す
val p3 = Person(name = "user_3", age = 24)
println("user_3 の年齢: ${p3.age}")
// セカンダリコンストラクター
val rect = Rectangle(4.0, 3.0)
val square = Rectangle(5.0) // 正方形
println("長方形の面積: ${rect.area}") // 12.0
println("正方形の面積: ${square.area}") // 25.0
// ファクトリーパターン
val db = Database.create("jdbc:mysql://localhost/mydb")
println("接続先: ${db.url}")
// init での検証(不正な引数は例外になります)
try {
Person("", 25)
} catch (e: IllegalArgumentException) {
println("エラー: ${e.message}")
}
}
class_constructor.kt
kotlinc class_constructor.kt -include-runtime -d class_constructor.jar java -jar class_constructor.jar Person インスタンス生成: user_1 (20歳) こんにちは、user_1です! Person インスタンス生成: user_2 (20歳) user_2 のメール: '' Person インスタンス生成: user_3 (24歳) user_3 の年齢: 24 長方形の面積: 12.0 正方形の面積: 25.0 データベース接続: jdbc:mysql://localhost/mydb 接続先: jdbc:mysql://localhost/mydb エラー: 名前は空にできません
よくあるミス
NG例1: プライマリコンストラクターに val/var を付け忘れるとプロパティにならない。
mistake1_no_val.kt
class Member(name: String, score: Int) // name と score はパラメーターのみ
fun main() {
val m = Member("user_1", 100)
// println(m.name) // コンパイルエラー: プロパティではないのでアクセス不可
}
val/var を付けるとプロパティになる。
fix1_with_val.kt
class Member(val name: String, var score: Int)
fun main() {
val m = Member("user_2", 120)
println("${m.name}: ${m.score}")
}
コンパイルして実行すると次のようになります。
kotlinc fix1_with_val.kt -include-runtime -d fix1_with_val.jar java -jar fix1_with_val.jar user_2: 120
NG例2: セカンダリコンストラクターがプライマリコンストラクターに委譲していないとコンパイルエラーになる。
mistake2_no_delegation.kt
class Team(val name: String) {
// コンパイルエラー: : this(...) で委譲しなければならない
// constructor(name: String, leader: String) {
// println("$name, $leader")
// }
}
: this(...) で委譲する。
fix2_delegation.kt
class Team(val name: String, val leader: String = "未定") {
constructor(name: String, leader: String, rank: Int) : this(name, leader) {
println("$name グループ (ランク $rank), リーダー: $leader")
}
}
fun main() {
val team = Team("project_x", "user_3", 1)
println(team.name)
}
コンパイルして実行すると次のようになります。
kotlinc fix2_delegation.kt -include-runtime -d fix2_delegation.jar java -jar fix2_delegation.jar project_x グループ (ランク 1), リーダー: user_3 project_x
NG例3: val/var なしのパラメーターは init ブロックでは使えるがメソッド内では使えない。
mistake3_no_property.kt
class Entity(name: String) {
init {
println("init: $name") // init 内では参照できる
}
// fun greet() = println("Hello, $name!") // コンパイルエラー: name は未解決の参照
}
val を付けてプロパティとして保持する。
fix3_val_property.kt
class Entity(val name: String) {
init {
println("init: $name")
}
fun greet() = println("Hello, $name!")
}
fun main() {
val entity = Entity("item_x")
entity.greet()
}
コンパイルして実行すると次のようになります。
kotlinc fix3_val_property.kt -include-runtime -d fix3_val_property.jar java -jar fix3_val_property.jar init: item_x Hello, item_x!
概要
Kotlinのクラスは、Javaと比べてコンストラクターの記述が大幅に簡潔です。プライマリコンストラクターにプロパティを直接定義できるため、Javaで必要だったフィールド宣言・コンストラクター本体・代入処理が1行に収まります。
複数の『init』ブロックを書くことも可能で、上から順に実行されます。セカンダリコンストラクターは必ずプライマリコンストラクターに委譲(『: this(...)』)する必要があります。
データ保持に特化したクラスはdata classを、継承・オーバーライドはopen / overrideを参照してください。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。