Saat membangun proyek nyata, tidak semua deklarasi boleh dipanggil dari mana saja. Kita perlu menyembunyikan detail implementasi dan hanya mengekspos API publik. Mekanisme itu diatur oleh visibility modifier. Pada chapter ini kita akan membahas empat modifier Kotlin — public, private, protected, dan internal — beserta perbedaan perilaku pada top-level declaration versus member declaration. Pemahaman ini akan kita pakai pada chapter internal Visibility dan Library Design.

Empat Modifier di Kotlin #

Berikut ringkasan keempat modifier:

ModifierTop-levelMember class
public (default)Tampak di mana saja.Tampak di mana saja jika class-nya juga public.
privateHanya di file yang sama.Hanya di dalam class yang sama.
protectedTidak boleh dipakai top-level.Hanya class tersebut dan subclass-nya.
internalHanya dalam modul yang sama.Hanya dalam modul yang sama.

Perbedaan Top-Level dan Member #

Deklarasi top-level (function, property, class pada luar class lain) dapat memakai public, private, atau internal. Modifier protected tidak diperbolehkan di tingkat top-level karena tidak ada konsep inheritance pada level tersebut. Sementara pada member class, keempat modifier dapat dipakai dan perilakunya bergantung pada kelas induk dan hubungan inheritance.

Contoh Kode #

Berikut contoh konkret yang memperlihatkan keempat modifier:

kotlin
// File: visibility_modifiers.kt
// Mendemonstrasikan modifier visibility: public, private, protected, internal.
package com.example.visibilitas

open class AkunBank(val pemilik: String) {
    // public (default) — dapat diakses dari mana saja.
    val mataUang: String = "IDR"

    // private — hanya dapat diakses di dalam class ini.
    private var saldo: Long = 0L

    // protected — hanya class ini dan subclass-nya.
    protected var catatan: String = "belum ada transaksi"

    // internal — dapat diakses dalam modul yang sama.
    internal val idInternal: String = "BANK-001"

    fun setor(jumlah: Long) {
        if (jumlah > 0) {
            saldo += jumlah
            catatan = "setor $jumlah"
        }
    }

    fun ambilSaldo(): Long = saldo
}

class AkunTabungan(pemilik: String) : AkunBank(pemilik) {
    fun ringkas(): String {
        // saldo tidak dapat diakses di sini (private di superclass).
        // catatan dapat diakses (protected di superclass).
        return "Pemilik: $pemilik, catatan: $catatan"
    }
}

fun main() {
    val akun = AkunBank("Budi")
    akun.setor(150_000)
    println("Pemilik: ${akun.pemilik}")
    println("Mata uang: ${akun.mataUang}")
    println("Saldo: ${akun.ambilSaldo()}")
    println("Catatan internal: ${akun.idInternal}")

    val tabungan = AkunTabungan("Siti")
    println(tabungan.ringkas())
}

// Top-level deklarasi: private hanya satu file, internal satu modul.
private const val RAHASIA_FILE: String = "konfigurasi lokal"
internal const val BAGIAN_MODUL: String = "tampak lintas file dalam modul"

fun aksesRahasia(): String = "Rahasia: $RAHASIA_FILE"
fun aksesBagianModul(): String = "Modul: $BAGIAN_MODUL"

Output yang Dihasilkan:

text
Pemilik: Budi
Mata uang: IDR
Saldo: 150000
Catatan internal: BANK-001
Pemilik: Siti, catatan: belum ada transaksi

Mari kita bedah kode di atas:

  1. Baris 5 (open class AkunBank): keyword open membuat class dapat di-subclass. Tanpa open, Kotlin menganggap class sebagai final dan tidak dapat diwariskan.
  2. Baris 7 (val mataUang: String = "IDR"): properti public. Karena public adalah default, kita tidak perlu menulis keyword-nya.
  3. Baris 10 (private var saldo: Long): properti private. Hanya dapat diakses dari dalam AkunBank. Subclass AkunTabungan tidak dapat melihat saldo secara langsung.
  4. Baris 13 (protected var catatan: String): properti protected. Subclass AkunTabungan dapat membaca catatan (lihat baris 26), tetapi kode di luar class hierarchy tidak dapat.
  5. Baris 16 (internal val idInternal): properti internal. Dapat diakses dari main() (baris 33) karena main() berada dalam modul yang sama dengan AkunBank.
  6. Baris 24-26 (class AkunTabungan : AkunBank): subclass yang membaca catatan (protected) tetapi tidak bisa membaca saldo (private). Pemilik pemilik adalah constructor parameter yang juga menjadi public properti karena val pada parameter constructor.
  7. Baris 41-42 (private const val RAHASIA_FILE, internal const val BAGIAN_MODUL): top-level constant. RAHASIA_FILE hanya tampak di file ini; BAGIAN_MODUL tampak lintas file dalam modul yang sama.

Perbedaan Platform #

Pada target JVM, modifier Kotlin dipetakan ke modifier Java saat runtime — private menjadi private, protected menjadi protected, internal menjadi public (dengan nama mangling agar panggilan dari Java terlihat aneh). Pada target Kotlin/JS dan Kotlin/Native, modifier internal ditegakkan secara lebih ketat pada level kompilator karena tidak ada batasan bytecode Java.

Referensi Lanjutan #

  • Packages — konteks visibility pada level package di panduan packages resmi
  • Visibility modifiers — panduan resmi modifier public, private, internal, dan protected

Selanjutnya #

Top-level declaration seperti private const di atas dapat dideklarasikan di luar class. Chapter File-Level Declarations akan membahas topik ini secara lebih mendalam.