今回はKotlinのクラス内に設定する可視性修飾子についてお話します。可視性修飾子によって、そのクラスの「カプセル化」を進めることができます。
これは「継承」や「ポリモーフィズム」と並んでオブジェクト指向プログラミングのキーワードであり、中でもカプセル化は非常に重要な概念です。
可視性修飾子の種類
まず始めに、可視性修飾子の種類を挙げておきましょう。Kotlinのクラスに設定できる可視性修飾子には4つの種類があります。
修飾子 | 意味 |
---|---|
public (デフォルト) | プログラムのどこからでもアクセス可能 |
private | そのクラスの内側からのみアクセス可能 |
protected | そのクラスか、そのクラスを継承するクラスからのみアクセス可能 |
internal | 同じモジュールの内側からのみアクセス可能 |
この中で特にprotectedとinternalについては、文章では若干分かりにくいかと思うので、イメージしにくいという方は以下の図で確認してみてください。
public:
private:
protected:
internal:
可視性修飾子を設定する
それではこれまでに作ったクラスを使って、可視性修飾子を設定していきます。
class Player(val name: String, var age: Int){
val job = "プロ野球選手"
var batting: Int? = null
var hits: Int? = null
init{
require(name.isNotEmpty()) {"名前を入力してください"}
}
constructor(name: String,
age: Int,
batting: Int,
hits: Int):this(name,age){
this.batting = batting
this.hits = hits
}
fun calcAvg():String{
val a = requireNotNull(batting)
val b = requireNotNull(hits)
val ans = String.format("%.3f",b.toDouble() / a.toDouble())
return "${ans[2]}割${ans[3]}分${ans[4]}厘"
}
}
この時点では可視性修飾子は設定されておらず、インスタンスを生成することによって、他のファイルからでもそのプロパティやメソッドにアクセスすることができます。
fun main() {
val yamada = Player("山田哲人",27,524,165)
println(yamada.hits)
println(yamada.calcAvg())
}
//165
//3割1分5厘
プロパティのhitsに可視性修飾子「private」を設定してみましょう。(メソッドに設定する場合も同じ要領でかまいません)
class Player(val name: String, var age: Int){
...
private var hits: Int? = null
...
}
この状態でmain関数をもう一度実行するとエラーになります。
//エラー:(3, 20) Kotlin: Cannot access 'hits': it is private in 'Player'
hitsプロパティにはmainメソッドのファイルからはアクセスできなくなりました。それではこの状態で、hitsプロパティを使用するcalcAvgメソッドはどうでしょう?
println(yamada.calcAvg()) //3割1分5厘
calcAvgメソッドはprivateなプロパティを参照するメソッドにもかかわらず、使用することができます。hitsを定義しているクラス内部では、hitsに対するアクセスが許容されているためです。
このように可視性修飾子はプロパティやメソッドへのアクセスを制限し、開発者が意図しない呼び出しを抑制することによって、プログラムの安全性を高めます。いわゆる隠蔽化です。
コンストラクタを隠蔽する
この可視性修飾子、実はコンストラクタにも設定することが可能です。Playerクラスのプライマリコンストラクタに可視性修飾子を設定してみましょう。
class Player private constructor(val name: String, var age: Int){
...
}
「クラス名 可視性修飾子 constructor(…)」とすることで、このクラスのプライマリコンストラクタはクラス内部でしか呼び出せず、外部からインスタンスを生成することができなくなります。
ただし今回使用しているPlayerクラスの場合は、セカンダリコンストラクタが定義されているため、セカンダリコンストラクタを使用したインスタンス生成は行うことができます。
コンストラクタを複数設定している場合、外部からのインスタンス生成をコントロールするには、コンストラクタ毎に可視性修飾子を設定しておきましょう。