【Kotlin】Properties and Fields: Getters, Setters

We clarified comparing basic Kotlin classes with Java classes about properties and fields.

Property


// Kotlin
class Human {
  val age = 20
}


// Decompiled to Java
public final class Human {
   private final int age = 20;

   public final int getAge() {
      return this.age;
   }
}


// Kotlin
class Human {
  var age = 20
}


// Decompiled to Java
public final class Human {
   private int age = 20;

   public final int getAge() {
      return this.age;
   }

   public final void setAge(int var1) {
      this.age = var1;
   }
}

Backing field


// Kotlin
class Human {
  var age = 20
    set(value) {
      field = value
    }
}


// Decompiled to Java
public final class Human {
   private int age = 20;

   public final int getAge() {
      return this.age;
   }

   public final void setAge(int value) {
      this.age = value;
   }
}

Backing property


// Kotlin
class Human {
  private var _age: Int = 20
  val age: Int
    get() {
      return _age
    }

  fun setAge(value: Int) {
    _age = value
  }
}


// Decompiled to Java
public final class Human {
   private int _age = 20;

   public final int getAge() {
      return this._age;
   }

   public final void setAge(int value) {
      this._age = value;
   }
}

Data class


// Kotlin
data class Human(val age: Int = 20)


// Decompiled to Java
public final class Human {
   private final int age;

   public final int getAge() {
      return this.age;
   }

   public Human(int age) {
      this.age = age;
   }

   // $FF: synthetic method
   public Human(int var1, int var2, DefaultConstructorMarker var3) {
      if ((var2 & 1) != 0) {
         var1 = 20;
      }

      this(var1);
   }

   public Human() {
      this(0, 1, (DefaultConstructorMarker)null);
   }

   public final int component1() {
      return this.age;
   }

   @NotNull
   public final Human copy(int age) {
      return new Human(age);
   }

   // $FF: synthetic method
   @NotNull
   public static Human copy$default(Human var0, int var1, int var2, Object var3) {
      if ((var2 & 1) != 0) {
         var1 = var0.age;
      }

      return var0.copy(var1);
   }

   @NotNull
   public String toString() {
      return "Human(age=" + this.age + ")";
   }

   public int hashCode() {
      return this.age;
   }

   public boolean equals(@Nullable Object var1) {
      if (this != var1) {
         if (var1 instanceof Human) {
            Human var2 = (Human)var1;
            if (this.age == var2.age) {
               return true;
            }
         }

         return false;
      } else {
         return true;
      }
   }
}

Below you can see how to decompile your class on Android Studio!!


[Tools]

  |

[Kotlin]

  |

[Show Kotlin Bytecode]

  |

[Decompile]



👉【Kotlin】バッキング・フィールド/プロパティ
👉 Properties and Fields: Getters, Setters, const, lateinit - Kotlin Programming Language


【Kotlin】バッキング・フィールド/プロパティ

フィールド

Fields cannot be declared directly in Kotlin classes.
Kotlin クラスでは、直接にフィールドを宣言することはできません。

プロパティ


// Kotlin
class Human {
    val age = 20
}


// Java
public final class Human {
   private final int age = 20;

   public final int getAge() {
      return this.age;
   }
}

バッキング・フィールド

ゲッターやセッターにカスタムロジックを入れたい場合は、「バッキング・フィールド」を使うことができます。

カスタムゲッターやセッターのスコープ内で「field」にアクセスできます。


// Kotlin
var counter = 0
    set(value) {
        if (value >= 0) field = value
    }


// Kotlin
class Human {
    val age = 20
        get() {
            println("Age is: $field")
            return field
        }
}


// Java
public final class Human {
   private final int age = 20;

   public final int getAge() {
      String var1 = "Age is: " + this.age;
      System.out.println(var1);
      return this.age;
   }
}

バッキング・プロパティ

ゲッターやセッターの外でフィールドに直接アクセスしたいときなどに使います。

private なフィールドに_を付けて明示します。


// Kotlin
private var _table: Map<String, Int>? = null
public val table: Map<String, Int>
    get() {
        if (_table == null) {
            _table = HashMap() // Type parameters are inferred
        }
        return _table ?: throw AssertionError("Set to null by another thread")
    }


// Kotlin
class Human {
    private val _age: Int = 20
    val age: Int
        get() {
            return _age
        }

     val printAge = {
         println("Age is: $_age")
     }
}


// Java
public final class Human {
   private final int _age = 20;
   @NotNull
   private final Function0 printAge = (Function0)(new Function0() {
      public Object invoke() {
         this.invoke();
         return Unit.INSTANCE;
      }

      public final void invoke() {
         String var1 = "Age is: " + Human.this._age;
         System.out.println(var1);
      }
   });

   public final int getAge() {
      return this._age;
   }

   @NotNull
   public final Function0 getPrintAge() {
      return this.printAge;
   }
}

まとめ

Java にデコンパイルした状況を確認しながら進むと理解しやすいように思います。

👉【Kotlin】Properties and Fields: Getters, Setters
👉 Properties and Fields: Getters, Setters, const, lateinit - Kotlin Programming Language
👉 Backing properties in Kotlin – ProAndroidDev
👉【MVVM】 ViewModel の_プロパティ記述


Kotlin で書きたい「正しいシングルトン(Singleton)」

汎用性のある使えるシングルトン、

どのように書いてますか?


class Singleton private constructor() {

  // getInstance() ???

}

ここから、どんな getInstance() を?

いくつか。


fun getInstance(): Singleton {
  synchronized(this) {
    if(INSTANCE == null){
      INSTANCE = Singleton()
    }
    return INSTANCE!!
  }
}


companion object {
  private var INSTANCE: Singleton ? = null
  fun getInstance(): Singleton {
    if(INSTANCE == null){
      INSTANCE = Singleton()
    }
    return INSTANCE!!
  }
}


companion object {
  val INSTANCE = Singleton()
  fun  getInstance(): Singleton {
    return INSTANCE
  }
}


@Volatile private var INSTANCE: Singleton ? = null
fun getInstance(): Singleton {
  if(INSTANCE == null){
    synchronized(this) {
      INSTANCE = Singleton()
    }
  }
  return INSTANCE!!
}


companion object {
  @Volatile private var INSTANCE: Singleton ? = null
  fun getInstance(): Singleton {
    return INSTANCE?: synchronized(this){
      Singleton().also {
        INSTANCE = it
      }
    }
  }
}

Singleton Pattern — What you might be doing wrong! – Hacker Noon

正解?

Googleの人はこう書いてます。


class CheeseRepository(
  private val api: CheeseApi,
  private val db: CheeseDatabase,
  private val executor: Executor
) {

  companion object {
    private const val PAGE_SIZE = 30

    private var instance: CheeseRepository? = null

    fun getInstance(context: Context) = instance ?: synchronized(this) {
      instance ?: CheeseRepository(
          CheeseApi(),
          Room.databaseBuilder(context, CheeseDatabase::class.java, "cheese").build(),
          Executors.newFixedThreadPool(4)
      ).also { instance = it }
    }
  }

CheesePage/CheeseRepository.kt at master · yaraki/CheesePage

あと、Dagger の @Singleton もこのスタイルに変換されますので安心です。覚えておきたい記述です。

まとめ

なんだか気持ちが悪くても、
なかなか正解が見つけられないこと多くね? 最近。