Saya bereksperimen dengan kode ini:
interface Callee {
public void foo(Object o);
public void foo(String s);
public void foo(Integer i);
}
class CalleeImpl implements Callee
public void foo(Object o) {
logger.debug("foo(Object o)");
}
public void foo(String s) {
logger.debug("foo(\"" + s + "\")");
}
public void foo(Integer i) {
logger.debug("foo(" + i + ")");
}
}
Callee callee = new CalleeImpl();
Object i = new Integer(12);
Object s = "foobar";
Object o = new Object();
callee.foo(i);
callee.foo(s);
callee.foo(o);
Ini mencetak foo(Object o)
tiga kali. Saya berharap pemilihan metode mempertimbangkan jenis parameter yang sebenarnya (bukan yang dideklarasikan). Apakah saya melewatkan sesuatu? Apakah ada cara untuk mengubah kode ini agar dapat dicetak foo(12)
, foo("foobar")
dan foo(Object o)
?
foo(Object)
. Pada waktu proses, kelas objek tempat metode dipanggil menentukan penerapan metode itu yang dipanggil, dengan mempertimbangkan bahwa itu mungkin turunan dari subkelas dari tipe yang dideklarasikan yang menggantikan metode.Seperti disebutkan sebelumnya, resolusi overloading dilakukan pada waktu kompilasi.
Java Puzzlers memiliki contoh yang bagus untuk itu:
Teka-teki 46: Kasus Pembuat yang Membingungkan
Teka-teki ini memberi Anda dua konstruktor yang Membingungkan. Metode utama memanggil konstruktor, tetapi yang mana? Keluaran program tergantung pada jawabannya. Apa yang dicetak program itu, atau apakah itu legal?
Solusi 46: Kasus Pembuat yang Membingungkan
... Proses resolusi kelebihan beban Java beroperasi dalam dua fase. Tahap pertama memilih semua metode atau konstruktor yang dapat diakses dan dapat diterapkan. Fase kedua memilih metode atau konstruktor yang paling spesifik yang dipilih pada fase pertama. Satu metode atau konstruktor kurang spesifik dari yang lain jika ia dapat menerima parameter yang diteruskan ke yang lain [JLS 15.12.2.5].
Dalam program kami, kedua konstruktor dapat diakses dan diterapkan. Konstruktor Confusing (Object) menerima parameter apapun yang diteruskan ke Confusing (double []) , jadi Confusing (Object) kurang spesifik. (Setiap larik ganda adalah Objek , tetapi tidak setiap Objek adalah larik ganda .) Oleh karena itu, konstruktor paling spesifik adalah Membingungkan (ganda []) , yang menjelaskan keluaran program.
Perilaku ini masuk akal jika Anda mengirimkan nilai bertipe double [] ; itu berlawanan dengan intuisi jika Anda meneruskan null . Kunci untuk memahami teka-teki ini adalah bahwa pengujian untuk metode atau konstruktor mana yang paling spesifik tidak menggunakan parameter sebenarnya : parameter yang muncul dalam pemanggilan. Mereka hanya digunakan untuk menentukan kelebihan beban yang berlaku. Setelah compiler menentukan overloading mana yang dapat diterapkan dan dapat diakses, compiler akan memilih overloading yang paling spesifik, dengan hanya menggunakan parameter formal: parameter yang muncul dalam deklarasi.
Untuk memanggil konstruktor Confusing (Object) dengan parameter null , tulis Confusing ((Object) null) baru . Ini memastikan bahwa hanya Confusing (Object) yang berlaku. Secara lebih umum, untuk memaksa compiler memilih overloading tertentu, masukkan parameter aktual ke tipe yang dideklarasikan dari parameter formal.
sumber
Kemampuan untuk mengirimkan panggilan ke suatu metode berdasarkan jenis argumen disebut pengiriman ganda . Di Jawa ini dilakukan dengan pola Pengunjung .
Namun, karena Anda berurusan dengan
Integer
s danString
s, Anda tidak dapat dengan mudah menggabungkan pola ini (Anda tidak dapat memodifikasi kelas-kelas ini). Jadi, waktu berjalan raksasaswitch
di objek akan menjadi senjata pilihan Anda.sumber
Di Java, metode untuk memanggil (seperti di mana tanda tangan metode yang akan digunakan) ditentukan pada waktu kompilasi, begitu juga dengan tipe waktu kompilasi.
Pola tipikal untuk mengatasi hal ini adalah dengan memeriksa tipe objek dalam metode dengan tanda tangan Objek dan mendelegasikan ke metode dengan cast.
Jika Anda memiliki banyak tipe dan ini tidak dapat dikelola, maka overloading metode mungkin bukan pendekatan yang tepat, melainkan metode publik seharusnya hanya mengambil Object dan mengimplementasikan beberapa jenis pola strategi untuk mendelegasikan penanganan yang sesuai per tipe objek.
sumber
Saya memiliki masalah serupa dengan memanggil konstruktor yang tepat dari kelas yang disebut "Parameter" yang dapat mengambil beberapa jenis Java dasar seperti String, Integer, Boolean, Long, dll. Dengan adanya array Objek, saya ingin mengubahnya menjadi array objek Parameter saya dengan memanggil konstruktor paling spesifik untuk setiap Objek dalam larik input. Saya juga ingin mendefinisikan Parameter konstruktor (Object o) yang akan melempar IllegalArgumentException. Saya tentu saja menemukan metode ini dipanggil untuk setiap Objek dalam array saya.
Solusi yang saya gunakan adalah mencari konstruktor melalui refleksi ...
Tidak diperlukan contoh yang jelek, pernyataan sakelar, atau pola pengunjung! :)
sumber
Java melihat jenis referensi saat mencoba menentukan metode mana yang akan dipanggil. Jika Anda ingin memaksa kode Anda, Anda memilih metode yang 'benar', Anda dapat mendeklarasikan bidang Anda sebagai contoh dari jenis tertentu:
Anda juga bisa memasukkan param Anda sebagai tipe param:
sumber
Jika ada kecocokan persis antara jumlah dan jenis argumen yang ditentukan dalam pemanggilan metode dan tanda tangan metode dari metode yang kelebihan beban, maka metode itulah yang akan dipanggil. Anda menggunakan referensi Objek, jadi java memutuskan pada waktu kompilasi bahwa untuk parameter Objek, ada metode yang menerima Objek secara langsung. Jadi itu disebut metode itu 3 kali.
sumber