普段から当たり前のように使ってはいたものの、あまりきちんと理解していなかったプロパティについてざっと調べた内容をまとめました。
プロパティとは
Kotlinにおけるプロパティは、Javaにおける「フィールド+getter/setter」に相当するものだと理解しました。
("もの"という表現があまり好きではないのですが、対応する言葉が分からなかったので、ご存知の方がいれば教えていただきたいです…)
具体的には以下のように宣言します。
class User {
// immutableな場合はgetのみ可。
val id: Int = 0
// mutableな場合はget/setどちらも可。
protected var name: String = ""
}
Kotlinの可視性修飾子はデフォルトでpublic
になるので、これをJavaで書くと以下のようになります。
public class User {
// immutableな場合はgetterのみ宣言する。
private int id = 0;
public id getId() {
return this.id;
}
// mutableな場合はget/setどちらも宣言する。
private String name = "";
protected String getName() {
return this.name;
}
protected void setName(String name) {
this.name = name;
}
}
getter/setterのカスタマイズとバッキングフィールド
Kotlinでプロパティを宣言すると、以下のようなデフォルトのgetter/setterが暗黙的に宣言されます。
Javaにおけるフィールドに相当する値(?)へはfield
識別子によってアクセスできます。このfield
は「バッキングフィールド」と呼ばれています。
class User {
// immutableな場合はgetterのみ暗黙的に宣言される。
val id: Int = 0
// 実際に宣言されるわけではなく、あくまでイメージ。
get() {
return field
}
// mutableな場合はgetter/setterどちらも暗黙的に宣言される。
protected var name: String = ""
// 実際に宣言されるわけではなく、あくまでイメージ。
get() {
return field
}
set(value) {
field = value
}
}
getter/setterをカスタマイズする場合は、明示的にgetter/setterをプロパティの直下に宣言し、ブラケットの中身を実装する必要があります。
getter/setterの可視範囲に関するルール
getter/setterの可視範囲に関しては、以下のようなルールがあります。
- getterの可視範囲:プロパティに指定された可視範囲と同じでなければならない
- setterの可視範囲:プロパティに指定された可視範囲と同じかそれより狭い可視範囲でなければならない
可視性修飾子は以下の表の4種類で、可視範囲はpublic
> internal
> protected
> private
となります。
詳細は公式リファレンスをご参照ください。
|可視性修飾子|可視範囲(クラス内で付与された場合)|
|:--|:--|:--|
|public|どこでも|
|internal|同一モジュール内|
|protected|宣言されたクラス内+サブクラス|
|private|宣言されたクラス内のみ|
デフォルトのgetter/setterの可視範囲はプロパティに付与されたものと同じ可視範囲になります。
getter/setterそれぞれに可視性修飾子を付与し可視範囲を変更することができますが、上記のルールに準拠する必要があります。
class User {
val id: Int = 0
private get // これは不可。getterの可視範囲はpublicでなければならない。
protected var name: String = ""
get // これは可。getterの可視範囲はprotected。
public set // これは不可。setterの可視範囲はprotected or privateでなければならない。
}
setterの可視範囲を広げたい場合
この方法を知りたくてプロパティについて調べ始めました。
結論としては、私が調べた範囲ではsetterに相当するメソッドを追加で宣言するしかなさそうです。
(他にあれば教えていただきたいです)
具体例として、以下のようなActivityとAdapterがあり、AdapterはOnItemClickListener
の実装クラスの参照を受け取りたい一方で、参照を受け取るプロパティ自体は公開したくないといったケースを考えます。
この場合、listener
プロパティの可視性修飾子をprivate
にしつつ、setterに相当するメソッド(setItemClickListener(listener)
)の可視性修飾子をpublic
にすることで、setterの可視範囲を擬似的に広げることが可能になります。
class HogeActivity : AppCompatActivity(), HogeAdapter.OnItemClickListener {
override onCreate(savedInstanceState: Bundle?) {
...
val adapter = HogeAdapter()
adapter.setOnItemClickListener(this)
}
override fun onClick(position: Int) {
...
}
}
class HogeAdapter {
interface OnItemClickListener {
fun onClick(position: Int)
}
private var listener: OnItemClickListener? = null
fun setOnItemClickListener(listener: OnItemClickListener) {
this.listener = listener
}
...
}
取り留めのない文章になってしまいましたが、以上となります。