Backing field adalah penyimpanan internal yang berada di balik sebuah property. Saat kita menulis var x: Int = 0, kompilator Kotlin secara otomatis menyediakan field internal serta getter dan setter default. Field ini tidak memiliki nama yang bisa kita pakai langsung — satu-satunya cara mengaksesnya dari dalam custom accessor adalah melalui keyword field. Pada chapter ini kita akan memahami kapan backing field tersedia, mengapa keyword field penting, dan bagaimana menghindari jebakan setter rekursif.
Kapan Backing Field Tersedia #
Backing field hadir otomatis bila salah satu kondisi berikut terpenuhi:
- Property menggunakan default getter dan default setter (kasus paling sederhana).
- Property memakai custom accessor yang mereferensikan keyword
field.
Bila sebuah property memiliki custom getter yang tidak memakai field dan tidak memiliki initializer, kompilator tidak akan membuat field. Inilah mekanisme yang membuat computed property (seperti luas pada chapter sebelumnya) tidak menyita memori untuk field yang tidak pernah dipakai.
| Konfigurasi property | Backing field? |
|---|---|
var x: Int = 0 | Ya (default accessor) |
val x: Int = 0 | Ya |
var x: Int = 0; get() = field * 2 | Ya (getter memakai field) |
val luas: Double get() = r * r | Tidak (computed property) |
var x: Int get() = hitung(); set(v) { simpan(v) } | Tidak (tidak memakai field) |
Keyword field Hanya di Custom Accessor #
Keyword field bukan variabel biasa. Keyword ini hanya dapat dipakai di dalam badan custom getter atau setter, dan hanya merujuk ke field internal dari property yang mengandung accessor tersebut. Di luar accessor — misalnya di dalam method atau function lain — keyword field tidak dapat dipakai.
Penggunaan keyword field paling umum adalah di custom setter. Saat pemanggil menulis t.celsius = 25.0, setter dijalankan dengan parameter nilai = 25.0. Untuk menyimpan nilai tersebut ke field internal, kita menulis field = nilai. Tidak ada cara lain untuk menugaskan ke field internal dari dalam setter.
Menghindari Setter Rekursif #
Bila kita menulis celsius = nilai di dalam setter property celsius, kompilator akan menafsirkan celsius = ... sebagai pemanggilan setter itu sendiri. Setter memanggil dirinya sendiri tanpa henti hingga stack overflow terjadi. Keyword field memutus siklus tersebut karena menugaskan langsung ke field internal, bukan melalui setter.
Contoh berikut mendemonstrasikan penggunaan field untuk validasi suhu dalam Termometer dan pemotongan nilai skor dalam TabelSkor. Pada kedua kasus, field menjadi satu-satunya jalur penyimpanan yang aman.
// backing_fields.kt
// Mendemonstrasikan keyword `field` pada custom setter untuk menghindari rekursi.
class Termometer {
var celsius: Double = 0.0
set(nilai) {
require(nilai >= -273.15) { "Suhu di bawah nol mutlak" }
field = nilai
}
val fahrenheit: Double
get() = celsius * 9 / 5 + 32
}
class TabelSkor {
var skor: Int = 0
set(nilai) {
// Memotong nilai ke rentang 0..100 sebelum disimpan.
field = nilai.coerceIn(0, 100)
}
}
fun main() {
val t = Termometer()
t.celsius = 25.0
println("Celsius: ${t.celsius}, Fahrenheit: ${t.fahrenheit}")
t.celsius = -10.0
println("Celsius: ${t.celsius}, Fahrenheit: ${t.fahrenheit}")
val s = TabelSkor()
s.skor = 75
println("Skor: ${s.skor}")
s.skor = 150
println("Skor setelah set 150: ${s.skor}")
s.skor = -20
println("Skor setelah set -20: ${s.skor}")
}Output yang Dihasilkan:
Celsius: 25.0, Fahrenheit: 77.0
Celsius: -10.0, Fahrenheit: 14.0
Skor: 75
Skor setelah set 150: 100
Skor setelah set -20: 0Mari kita bedah kode tersebut:
var celsius: Double = 0.0dengan custom setter: setter menerimanilai, memvalidasi denganrequire(nilai >= -273.15), lalu menugaskanfield = nilai. Penugasan kefieldmenyimpan nilai ke penyimpanan internal tanpa memanggil setter lagi.val fahrenheit: Double get() = celsius * 9 / 5 + 32: computed property tanpa backing field. Getter membaca propertycelsius(yang memiliki field sendiri), mengalikan dengan9/5, lalu menambah32. Karenafahrenheittidak memakai keywordfield, kompilator tidak menyediakan field untuknya.t.celsius = -10.0: validasi lolos karena-10.0 >= -273.15. Field internalcelsiusdiset ke-10.0. Pemanggilant.fahrenheitkemudian mengembalikan-10 * 9 / 5 + 32 = 14.0.field = nilai.coerceIn(0, 100): function standarcoerceInmemotong nilai ke rentang yang ditentukan. Saat pemanggil menuliss.skor = 150, setter menerima150, memotong ke100, lalu menyimpan100ke field internal. Saats.skor = -20, nilai dipotong ke0.- Penugasan aman: bila kita mengganti
field = nilaidengancelsius = nilaidi dalam setterTermometer, kompilator akan menyusun pemanggilan setter yang sama lagi tanpa henti. Hasilnya bukan kesalahan kompilasi, melainkanStackOverflowErrorsaat runtime — jebakan yang harus dihindari.
Backing Field pada Property val #
Property val hanya memiliki getter, tidak memiliki setter. Karena val hanya ditugaskan satu kali (saat inisialisasi), custom getter pada val jarang memerlukan field. Bila sebuah val memiliki initializer = ... dan custom getter yang memakai field, kompilator menyediakan field yang diisi saat inisialisasi dan dibaca oleh getter. Pola ini berguna saat kita ingin menyimpan nilai sambil tetap mengubah cara ia dibaca dari luar.
Batasan Keyword field #
Keyword field memiliki tiga batasan yang perlu diingat:
- Hanya tersedia di dalam custom getter atau setter, bukan di method biasa.
- Hanya merujuk ke field dari property yang mengandung accessor tersebut; tidak bisa dipakai untuk membaca field property lain.
- Bila sebuah property memiliki custom accessor yang tidak memakai
fieldsama sekali dan tidak memiliki initializer, kompilator tidak menyediakan field — property menjadi computed property.
Referensi Lanjutan #
- Properties
— penjelasan resmi backing field dengan identifier
field
Ringkasan #
Backing field adalah penyimpanan internal yang otomatis tersedia bila property membutuhkannya. Keyword field menjadi satu-satunya jalur aman menugaskan ke field internal dari dalam custom setter, sekaligus mencegah rekursi tak terbatas. Property val dan var tanpa referensi field tidak memiliki field dan menjadi computed property. Pada chapter Visibility Modifiers berikutnya, kita akan melihat bagaimana backing field dapat dilindungi lebih jauh dengan modifier akses seperti private dan protected.