Primary constructor tidak selalu cukup untuk semua situasi pembuatan object. Terkadang pemanggil hanya tahu sebagian argumen, atau ingin membangun object dari format data berbeda seperti string terpisah koma. Untuk kasus tersebut, Kotlin menyediakan secondary constructor yang dideklarasikan dengan keyword constructor di dalam body class. Pada chapter ini kita akan mempelajari sintaks secondary constructor, aturan delegasi wajib ke primary constructor, dan kapan secondary constructor lebih tepat dibanding default argument.

Sintaks Secondary Constructor #

Secondary constructor dideklarasikan di dalam body class dengan keyword constructor diikuti daftar parameter dalam tanda kurung. Karena primary constructor sudah memegang inisialisasi property utama, setiap secondary constructor wajib mendelegasikan ke primary constructor (atau ke secondary constructor lain) melalui keyword this.

kotlin Contoh: secondary constructor mendelegasikan ke primary
class Peliharaan(val nama: String, val umur: Int) {
    constructor(nama: String) : this(nama, 0)
}

Tanda : this(nama, 0) berarti secondary constructor memanggil primary constructor dengan argumen nama dan 0. Setelah delegasi selesai, body secondary constructor (bila ada) dijalankan setelah init block primary.

Aturan Delegasi #

Tabel berikut merangkum aturan utama secondary constructor:

AturanKonsekuensi
Wajib mendelegasikan ke primaryTidak boleh melewati inisialisasi property utama
Delegasi melalui this(...)Bukan super(...) kecuali ada inheritance
Boleh memiliki body sendiriDieksekusi setelah init block primary selesai
Boleh lebih dari satuSelama tidak ada dua constructor dengan signature sama

Bila sebuah class tidak memiliki primary constructor, secondary constructor boleh langsung mendelegasikan ke superclass. Namun bila primary constructor ada, jalur delegasi harus berakhir pada primary constructor (langsung atau melalui rangkaian secondary constructor lain).

Contoh Beberapa Secondary Constructor #

Contoh berikut mendefinisikan class Peliharaan dengan primary constructor dua parameter, lalu menambahkan dua secondary constructor untuk situasi berbeda: pembuatan tanpa umur, dan pembuatan dengan flag apakah umur diketahui.

kotlin
// peliharaan_sekunder.kt
// Mendemonstrasikan secondary constructor yang mendelegasikan ke primary constructor.

class Peliharaan(val nama: String, val umur: Int) {
    // Secondary constructor: hanya nama, umur default 0.
    constructor(nama: String) : this(nama, 0)

    // Secondary constructor: nama dan flag apakah umur diketahui.
    constructor(nama: String, umurDiketahui: Boolean) : this(
        nama,
        if (umurDiketahui) 1 else 0
    )

    fun deskripsi(): String {
        val umurTeks = if (umur == 0) "belum diketahui" else "$umur tahun"
        return "$nama, umur $umurTeks."
    }
}

fun main() {
    val a = Peliharaan("Miko")
    println(a.deskripsi())

    val b = Peliharaan("Rex", 4)
    println(b.deskripsi())

    val c = Peliharaan("Doni", false)
    println(c.deskripsi())
}

Output yang Dihasilkan:

text
Miko, umur belum diketahui.
Rex, umur 4 tahun.
Doni, umur belum diketahui.

Mari kita bedah bagian-bagiannya:

  1. constructor(nama: String) : this(nama, 0): secondary constructor menerima satu argumen nama. Tanda : this(nama, 0) mendelegasikan ke primary constructor dengan umur = 0. Pemanggil Peliharaan("Miko") akan masuk ke constructor ini.
  2. constructor(nama: String, umurDiketahui: Boolean) : this(nama, if (umurDiketahui) 1 else 0): secondary constructor menerima argumen berbeda — String dan Boolean — sehingga tidak bentrok dengan primary constructor (String, Int). Signature di Kotlin ditentukan oleh jumlah dan tipe parameter, bukan nama.
  3. Peliharaan("Miko"): kompilator memilih secondary constructor satu parameter. Karena umur diisi 0, method deskripsi() menampilkan teks "belum diketahui".
  4. Peliharaan("Rex", 4): kompilator memilih primary constructor langsung karena signature paling cocok. Tidak ada secondary constructor yang dipanggil.
  5. Peliharaan("Doni", false): kompilator memilih secondary constructor (String, Boolean). Karena umurDiketahui = false, nilai 0 diteruskan ke primary constructor.

Secondary Constructor vs Default Argument #

Sebagian besar kasus yang dahulu membutuhkan secondary constructor di Java dapat diselesaikan dengan default argument pada primary constructor di Kotlin:

kotlin Contoh: primary constructor dengan default argument
class Peliharaan(val nama: String, val umur: Int = 0)

Deklarasi di atas memungkinkan pemanggilan Peliharaan("Miko") dan Peliharaan("Rex", 4) tanpa menulis secondary constructor apa pun. Gunakan secondary constructor hanya bila jalur pembuatan object benar-benar berbeda secara semantik — misalnya memerlukan konversi tipe data atau memerlukan body yang melakukan efek samping setelah delegasi.

Body Secondary Constructor #

Secondary constructor dapat memiliki body sendiri yang ditulis setelah tanda kurung delegasi. Body ini dijalankan setelah primary constructor selesai, termasuk setelah semua init block. Urutan ini penting karena memastikan semua property sudah siap saat body secondary constructor dieksekusi.

kotlin Contoh: secondary constructor dengan body
class Catatan(val judul: String, val isi: String) {
    constructor(judul: String) : this(judul, "") {
        println("Catatan kosong dibuat: $judul")
    }
}

Pada contoh di atas, println dijalankan setelah primary constructor selesai mengisi judul dan isi. Pemanggil yang membuat Catatan("Hari Ini") akan melihat pesan tersebut tercetak ke layar.

Referensi Lanjutan #

Ringkasan #

Secondary constructor adalah pelengkap primary constructor untuk situasi pembuatan object dengan jalur berbeda. Setiap secondary constructor wajib mendelegasikan ke primary constructor melalui this(...). Bila kebutuhan hanya menyediakan nilai default, gunakan default argument pada primary constructor karena lebih ringkas dan lebih idiomatik. Pada chapter init Blocks berikutnya, kita akan membedah lebih dalam urutan eksekusi property initializer dan init block, yang menjadi fondasi penting bagi pemahaman secondary constructor.