言語
日本語
English

Caution

お使いのブラウザはJavaScriptが無効になっております。
当サイトでは検索などの処理にJavaScriptを使用しています。
より快適にご利用頂くため、JavaScriptを有効にしたうえで当サイトを閲覧することをお勧めいたします。

Kotlin辞典

  1. トップページ
  2. Kotlin辞典
  3. class / コンストラクター

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を参照してください。

記事の間違いや著作権の侵害等ございましたらお手数ですがまでご連絡頂ければ幸いです。