LoginSignup
14
11

More than 3 years have passed since last update.

Kotlinのプロパティとは

Last updated at Posted at 2019-08-06

普段から当たり前のように使ってはいたものの、あまりきちんと理解していなかったプロパティについてざっと調べた内容をまとめました。

プロパティとは

Kotlinにおけるプロパティは、Javaにおける「フィールド+getter/setter」に相当するものだと理解しました。
("もの"という表現があまり好きではないのですが、対応する言葉が分からなかったので、ご存知の方がいれば教えていただきたいです…)

具体的には以下のように宣言します。

User.kt
class User {

  // immutableな場合はgetのみ可。
  val id: Int = 0

  // mutableな場合はget/setどちらも可。
  protected var name: String = ""

}

Kotlinの可視性修飾子はデフォルトでpublicになるので、これをJavaで書くと以下のようになります。

User.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は「バッキングフィールド」と呼ばれています。

User.kt
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それぞれに可視性修飾子を付与し可視範囲を変更することができますが、上記のルールに準拠する必要があります。

User.kt
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
  }

  ...

}

取り留めのない文章になってしまいましたが、以上となります。

14
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
11