Dua metode boleh memakai nama yang sama selama keduanya bisa dibedakan dari daftar parameternya. Mekanisme ini disebut overloading, dan kompilatorlah yang memilih versi mana yang dijalankan pada setiap pemanggilan. Topik ini membahas batasan signature, contoh overloading yang sehat, urutan resolusi yang dipakai kompilator, serta bentuk overload yang membuat pemilihannya gagal. Pemahaman ini penting karena hampir semua pustaka bawaan Java menamai metode-metodenya dengan cara yang sama.
Signature menentukan keunikan#
Signature sebuah metode terdiri atas namanya dan urutan tipe parameternya, dan itu saja. Tipe kembalian serta nama parameter tidak terhitung bagian dari signature, sehingga tidak bisa dipakai untuk membedakan dua metode. Tabel berikut membandingkan beberapa deklarasi terhadap metode dasar cetak(int).
| Deklarasi | Signature | Bisa hidup berdampingan |
|---|---|---|
void cetak(int nilai) | cetak(int) | menjadi pembandingnya |
void cetak(int awal, int akhir) | cetak(int, int) | ya, jumlah parameternya berbeda |
void cetak(double nilai) | cetak(double) | ya, tipe parameternya berbeda |
int cetak(int nilai) | cetak(int) | tidak, signature-nya sama |
// tidak-dijalankan
static double konversi(double celsius) {
return celsius * 9.0 / 5.0 + 32.0;
}
static int konversi(double celsius) { // ditolak: signature sama dengan di atas
return (int) Math.round(celsius * 9.0 / 5.0 + 32.0);
}Pasangan pada contoh di atas ditolak kompilator dengan pesan bahwa metode tersebut sudah didefinisikan, meskipun tipe kembaliannya berbeda. Perbaikannya ada dua, yaitu mengubah daftar parameternya agar signature-nya ikut berubah, atau memberi nama metode yang lain. Nama yang berbeda sering kali lebih jelas daripada memaksakan satu nama untuk dua hasil yang berbeda tipenya.
Overloading lewat jumlah dan tipe parameter#
Overloading paling sehat dipakai untuk pekerjaan yang semakna dengan bentuk masukan berbeda. Satu nama mencetak berbagai jenis nilai, atau satu nama menghitung total dari jumlah argumen yang berbeda, dan setiap versi memiliki tubuh sendiri.
public class CetakSerbaguna {
static void cetak(int nilai) {
System.out.println("cetak(int): " + nilai);
}
static void cetak(int awal, int akhir) {
System.out.println("cetak(int, int): " + awal + " sampai " + akhir);
}
static void cetak(double nilai) {
System.out.println("cetak(double): " + nilai);
}
static void cetak(String teks) {
System.out.println("cetak(String): " + teks);
}
public static void main(String[] args) {
cetak(42);
cetak(1, 4);
cetak(3.14);
cetak("selesai");
}
}cetak(int): 42
cetak(int, int): 1 sampai 4
cetak(double): 3.14
cetak(String): selesaiEmpat overload cetak hidup berdampingan karena keempat signature-nya berbeda. Pada setiap baris pemanggilan, kompilator membaca tipe argumen yang tertulis lalu menetapkan versi yang dijalankan, dan keputusan itu sudah final sebelum program berjalan. Karena diputuskan saat kompilasi berdasarkan tipe yang tampak pada kode, overloading berbeda dari mekanisme pemilihan berbasis objek yang bekerja saat program berjalan.
Cara kompilator memilih#
Bila tipe argumen tidak persis sama dengan parameter versi mana pun, kompilator memakai urutan pilihan yang tetap. Kecocokan persis datang terlebih dahulu, lalu pelebaran tipe (widening) seperti int menjadi long atau double, kemudian autoboxing ke tipe pembungkus seperti Integer, dan terakhir varargs. Penyempitan tipe tidak pernah dilakukan secara otomatis, sehingga pemanggilan yang hanya bisa terpenuhi lewat penyempitan ditolak.
public class UjiResolusi {
static void proses(int nilai) {
System.out.println("proses(int) terpilih: " + nilai);
}
static void proses(double nilai) {
System.out.println("proses(double) terpilih: " + nilai);
}
public static void main(String[] args) {
proses(7);
proses(7L);
proses(2.5f);
}
}proses(int) terpilih: 7
proses(double) terpilih: 7.0
proses(double) terpilih: 2.5Pemanggilan pertama membawa int yang cocok persis dengan proses(int), sehingga pelebaran tidak perlu. Pemanggilan proses(7L) membawa long yang tidak bisa menyempit menjadi int, tetapi melebar menjadi double, sehingga versi double terpilih dan nilainya tercetak sebagai 7.0. Pemanggilan terakhir membawa float yang juga melebar ke double. Bila versi double tidak ada, dua pemanggilan terakhir akan gagal dikompilasi karena satu-satunya kandidat menuntut penyempitan.
Bila kompilator bingung#
Bentuk overload tertentu membuat dua versi sama-sama layak sehingga kompilator menyerah dengan pesan bahwa rujukannya ambigu. Dua metode pada contoh berikut masing-masing butuh tepat satu konversi untuk menerima pemanggilan kirim(5, 5), dan tidak ada aturan yang memihak salah satunya.
// tidak-dijalankan
static void kirim(int angka, long nomor) { }
static void kirim(long angka, int nomor) { }
// kirim(5, 5); // ditolak: kedua versi sama-sama butuh satu konversiHindarannya sederhana, yaitu merancang overload yang tidak saling bersaing pada pemanggilan yang sama. Bedakan jumlah parameternya, atau pilih tipe parameternya cukup berjauhan sehingga hanya ada satu jalur konversi terbaik. Bila dua overload terasa sama mudah terpilih, pembaca kode pun akan kesulitan menebak versi mana yang benar-benar berjalan.
Kesalahan umum#
- Mengira tipe kembalian membedakan overload. Dua metode
cetak(int)yang satu mengembalikanvoiddan satu lagiinttetap ditolak karena signature-nya sama. Ubah daftar parameternya atau beri nama lain. - Mengira nama parameter bagian dari signature. Deklarasi
cetak(int nilai)dancetak(int jumlah)bertabrakan karena urutan tipenya identik. - Merancang pasangan overload ambigu seperti
kirim(int, long)dankirim(long, int). Pemanggilan dengan dua literalinttidak punya pemenang dan kompilasi berhenti. - Mengharapkan penyempitan otomatis dari
doublekeint. Kompilator menolak pemanggilannya, dan argumen perlu dikonversi secara eksplisit lewat cast.
Ringkasan#
- Signature terdiri atas nama metode dan urutan tipe parameternya, sedangkan tipe kembalian dan nama parameter tidak termasuk.
- Overloading membolehkan nama yang sama selama signature-nya berbeda.
- Resolusi mengikuti urutan kecocokan persis, pelebaran, autoboxing, lalu varargs, tanpa penyempitan otomatis.
- Dua overload yang sama-sama butuh konversi menghasilkan pemanggilan ambigu dan menggagalkan kompilasi.
Referensi#
- Overloading Methods — Oracle — penjelasan overloading dan contoh pembeda parameternya pada Java Tutorials.
- Compile-Time Step 2: Determine Method Signature — JLS, Java SE 21 — urutan resolusi dari kecocokan persis sampai fase varargs.