KotlinDive

プログラミング言語 Kotlin についての入門ブログです。

クラス(ヴィジビリティ)

ヴィジビリティ修飾子

クラス、オブジェクト、インターフェース、コンストラクタ、関数、プロパティとそのセッターに対して、ヴィジビリティを設定することができます。
(ゲッターのヴィジビリティはプロパティのヴィジビリティと同じものになります)
Kotlinには、4種類のヴィジビリティ修飾子があります。

  • private
  • protected
  • internal
  • public

明示的にヴィジビリティ修飾子を設定しない場合、デフォルトのヴィジビリティ修飾子は「public」になります。

パッケージ

トップレベルに宣言されたクラス、オブジェクト、インターフェース、関数、プロパティのヴィジビリティは次の表のようになります。

ヴィジビリティ どこから見えるか
public(デフォルト) どこからでも参照可能
private 同じファイル内のみ参照可能
internal 同じモジュール内のみ参照可能
protected トップレベルで宣言したものには使用できない

example.kt


package visibilitytest

// getterにはどこからでも参照できる
var num: Int = 123
    // setterはこのファイル内でしか参照できない
    private set(value) {
        if (value < 0) {
            println("${value} は無効です")
            return
        }

        field = value
    }

// internalなので、この関数は同じモジュールからであれば参照できる
internal fun assignNum(value: Int) {
    num = value
}

main.kt


package visibilitytest

fun main(args: Array) {
    println("num = ${num}")
    assignNum(-321)

    // numのsetterはprivateなので、以下のコードはビルドエラー
    // num = -321
}

num = 123
-321 は無効です

クラス/インターフェースメンバー

クラスとインターフェースのメンバーのヴィジビリティは次の表のようになります.

ヴィジビリティ どこから見えるか
private 同じクラス/インターフェース(のメンバー)から参照可能
protected privateと同じ範囲+サブクラス(のメンバー)から参照可能
internal internalなメンバーを持つクラスが宣言されているモジュール内から参照可能
public(デフォルト) どこからでも参照可能

example.kt


package visibilitytest

import java.nio.DoubleBuffer

open class Person(name: String) {
    var name = name
        protected set(value) {
            if (value.isEmpty()) {
                println("Empty name is invalid")
                return
            }

            field = value
        }

    internal fun printName() = println("Name is ${name}.")
}

class Student(name: String, score: Double) : Person(name) {
    var score = score

    fun toUpperCaseName() {
        // name のsetterはprotectedなので、サブクラスではアクセルできる
        name = name.toUpperCase()
    }
}

class PersonDescriber(someone: Person) {
    val someone = someone

    fun describe() {
        // printName はinternalなので、同じモジュール内では参照できる
        someone.printName()
    }
}

main.kt


import visibilitytest.Student
import visibilitytest.PersonDescriber

fun main(args: Array) {
    val student = Student("suzuki taro", 80.0)
    println("student is ${student.name}")
    student.toUpperCaseName()

    val desc = PersonDescriber(student)
    desc.describe()
}

student is suzuki taro
Name is SUZUKI TARO.

プライマリコンストラクタ

プライマリコンストラクタにヴィジビリティを設定したい場合、明示的にconstructorキーワードをつける必要があります。

example.kt


package visibilitytest

// プライマリコンストラクタにprotectedを設定
open class Person protected constructor(name: String) {
    var name = name
        protected set(value) {
            if (value.isEmpty()) {
                println("Empty name is invalid")
                return
            }

            field = value
        }

    internal fun printName() = println("Name is ${name}.")
}

class Student(name: String, score: Double) : Person(name) {
    var score = score

    fun toUpperCaseName() {
        // name のsetterはprotectedなので、サブクラスではアクセルできる
        name = name.toUpperCase()
    }
}

class PersonDescriber(someone: Person) {
    val someone = someone

    fun describe() {
        // printName はinternalなので、同じモジュール内では参照できる
        someone.printName()
    }
}

main.kt


import visibilitytest.Person
import visibilitytest.Student
import visibilitytest.PersonDescriber

fun main(args: Array) {
    val student = Student("suzuki taro", 80.0)
    println("student is ${student.name}")
    student.toUpperCaseName()

    val desc = PersonDescriber(student)
    desc.describe()

    // Personのプライマリコンストラクタはprotectedであり、ここからはアクセスできない
    // そのため、直接Personをインスタンス化することはできない
    // 以下のコードはビルドエラー
    // val person = Person("someone")
}