Kemarin saya melakukan wawancara telepon teknis selama dua jam (yang saya lulus, woohoo!), Tetapi saya benar-benar meredam pertanyaan berikut tentang dynamic binding di Java. Dan ini sangat membingungkan karena saya dulu mengajarkan konsep ini kepada mahasiswa ketika saya masih menjadi TA beberapa tahun yang lalu, jadi kemungkinan bahwa saya memberi mereka informasi yang salah sedikit mengganggu ...
Inilah masalah yang saya berikan:
/* What is the output of the following program? */
public class Test {
public boolean equals( Test other ) {
System.out.println( "Inside of Test.equals" );
return false;
}
public static void main( String [] args ) {
Object t1 = new Test();
Object t2 = new Test();
Test t3 = new Test();
Object o1 = new Object();
int count = 0;
System.out.println( count++ );// prints 0
t1.equals( t2 ) ;
System.out.println( count++ );// prints 1
t1.equals( t3 );
System.out.println( count++ );// prints 2
t3.equals( o1 );
System.out.println( count++ );// prints 3
t3.equals(t3);
System.out.println( count++ );// prints 4
t3.equals(t2);
}
}
Saya menegaskan bahwa output seharusnya berupa dua pernyataan cetak terpisah dari dalam equals()
metode yang diganti : at t1.equals(t3)
dan t3.equals(t3)
. Kasus terakhir cukup jelas, dan dengan kasus sebelumnya, meskipun t1
memiliki referensi tipe Object, itu dibuat sebagai tipe Test, sehingga pengikatan dinamis harus memanggil bentuk metode yang diganti.
Sepertinya tidak. Pewawancara saya mendorong saya untuk menjalankan program sendiri, dan lihatlah, hanya ada satu keluaran dari metode yang diganti: di telepon t3.equals(t3)
.
Pertanyaan saya kemudian adalah, mengapa? Seperti yang sudah saya sebutkan, meskipun t1
merupakan referensi dari tipe Objek (jadi pengikatan statis akan memanggil equals()
metode Object ), pengikatan dinamis harus menjaga pemanggilan versi paling spesifik dari metode berdasarkan tipe referensi yang dipakai. Apa yang saya lewatkan?
sumber
Jawaban:
Java menggunakan pengikatan statis untuk metode yang kelebihan beban, dan pengikatan dinamis untuk metode yang diganti. Dalam contoh Anda, metode sama dengan kelebihan beban (memiliki tipe param yang berbeda dari Object.equals ()), sehingga metode yang dipanggil terikat ke tipe referensi pada waktu kompilasi.
Beberapa diskusi di sini
Fakta bahwa ini adalah metode yang sama tidak terlalu relevan, selain itu adalah kesalahan umum untuk membebani dan menimpanya, yang sudah Anda sadari berdasarkan jawaban Anda atas masalah dalam wawancara.
Edit: Deskripsi yang bagus juga di sini . Contoh ini menunjukkan masalah serupa yang terkait dengan jenis parameter, tetapi disebabkan oleh masalah yang sama.
Saya percaya jika pengikatan sebenarnya dinamis, maka setiap kasus di mana pemanggil dan parameternya adalah turunan dari Test akan menghasilkan metode yang diganti dipanggil. Jadi t3.equals (o1) akan menjadi satu-satunya case yang tidak dapat dicetak.
sumber
The
equals
metodeTest
tidak mengesampingkanequals
metodejava.lang.Object
. Lihat tipe parameternya! TheTest
kelas overloadingequals
dengan metode yang menerimaTest
.Jika
equals
metode ini dimaksudkan untuk diganti, metode ini harus menggunakan anotasi @Override. Ini akan menyebabkan kesalahan kompilasi untuk menunjukkan kesalahan umum ini.sumber
Yang cukup menarik, dalam kode Groovy (yang dapat dikompilasi ke file kelas), semua kecuali satu panggilan akan mengeksekusi pernyataan cetak. (Yang membandingkan Test dengan Object jelas tidak akan memanggil fungsi Test.equals (Test).) Ini karena groovy TIDAK melakukan pengetikan dinamis sepenuhnya. Ini sangat menarik karena tidak memiliki variabel yang diketik secara dinamis. Saya telah membaca di beberapa tempat bahwa ini dianggap berbahaya, karena programmer mengharapkan hal yang keren untuk java.
sumber
Java tidak mendukung co-variance dalam parameter, hanya dalam tipe kembalian.
Dengan kata lain, meskipun tipe kembalian Anda dalam metode penggantian mungkin merupakan subtipe dari apa yang telah ditimpa, itu tidak benar untuk parameter.
Jika parameter Anda untuk sama di Object adalah Object, menempatkan sama dengan apa pun di subclass akan menjadi metode overload, bukan override. Oleh karena itu, satu-satunya situasi di mana metode itu akan dipanggil adalah ketika tipe statis parameternya adalah Test, seperti dalam kasus T3.
Semoga berhasil dengan proses wawancara kerja! Saya ingin sekali diwawancarai di perusahaan yang menanyakan jenis pertanyaan ini daripada pertanyaan algo / struktur data biasa yang saya ajarkan kepada siswa saya.
sumber
Saya pikir kuncinya terletak pada fakta bahwa metode equals () tidak sesuai dengan standar: Dibutuhkan di objek Uji lain, bukan objek Objek dan dengan demikian tidak menimpa metode equals (). Ini berarti Anda sebenarnya hanya membebani itu untuk melakukan sesuatu yang istimewa ketika diberikan objek Uji sambil memberinya objek Object memanggil Object.equals (Object o). Melihat kode itu melalui IDE apa pun akan menunjukkan dua metode equals () untuk Test.
sumber
Metode ini kelebihan beban, bukan diganti. Sama selalu mengambil Objek sebagai parameter.
btw, Anda memiliki item tentang ini di Java efektif Bloch (yang harus Anda miliki).
sumber
Beberapa catatan di Dynamic Binding (DD) dan Static Binding̣̣̣ (SB) setelah pencarian beberapa saat:
1. Waktu eksekusi : (Ref.1)
2. Digunakan untuk :
Referensi:
sumber
Jika metode lain ditambahkan yang menggantikan alih-alih membebani, itu akan menjelaskan panggilan pengikatan dinamis pada waktu proses.
/ * Apa output dari program berikut? * /
public class DynamicBinding { public boolean equals(Test other) { System.out.println("Inside of Test.equals"); return false; } @Override public boolean equals(Object other) { System.out.println("Inside @override: this is dynamic binding"); return false; } public static void main(String[] args) { Object t1 = new Test(); Object t2 = new Test(); Test t3 = new Test(); Object o1 = new Object(); int count = 0; System.out.println(count++);// prints 0 t1.equals(t2); System.out.println(count++);// prints 1 t1.equals(t3); System.out.println(count++);// prints 2 t3.equals(o1); System.out.println(count++);// prints 3 t3.equals(t3); System.out.println(count++);// prints 4 t3.equals(t2); } }
sumber
Saya menemukan artikel menarik tentang pengikatan dinamis vs. statis. Muncul dengan sepotong kode untuk mensimulasikan pengikatan dinamis. Itu membuat kode saya lebih mudah dibaca.
https://sites.google.com/site/jeffhartkopf/covariance
sumber
Jawaban atas pertanyaan "mengapa?" begitulah definisi bahasa Java.
Mengutip artikel Wikipedia tentang Kovarian dan Kontravarian :
Bahasa lain berbeda.
sumber
Sangat jelas, bahwa tidak ada konsep menimpa di sini. Ini adalah metode overloading. yang
Object()
metode kelas Object mengambil parameter acuan dari jenis Obyek dan iniequal()
metode mengambil parameter acuan tipe Test.sumber
Saya akan mencoba menjelaskan ini melalui dua contoh yang merupakan versi tambahan dari beberapa contoh yang saya temukan secara online.
public class Test { public boolean equals(Test other) { System.out.println("Inside of Test.equals"); return false; } @Override public boolean equals(Object other) { System.out.println("Inside of Test.equals ot type Object"); return false; } public static void main(String[] args) { Object t1 = new Test(); Object t2 = new Test(); Test t3 = new Test(); Object o1 = new Object(); int count = 0; System.out.println(count++); // prints 0 o1.equals(t2); System.out.println("\n" + count++); // prints 1 o1.equals(t3); System.out.println("\n" + count++);// prints 2 t1.equals(t2); System.out.println("\n" + count++);// prints 3 t1.equals(t3); System.out.println("\n" + count++);// prints 4 t3.equals(o1); System.out.println("\n" + count++);// prints 5 t3.equals(t3); System.out.println("\n" + count++);// prints 6 t3.equals(t2); } }
Di sini, untuk baris dengan nilai hitungan 0, 1, 2, dan 3; kita memiliki referensi dari Object untuk o1 dan t1 pada
equals()
metode. Jadi, pada waktu kompilasi,equals()
metode dari file Object.class akan dibatasi.Namun, meskipun referensi dari t1 adalah Object , ia memiliki intialization dari class Test .
Object t1 = new Test();
.Oleh karena itu, pada saat run-time itu memanggil
public boolean equals(Object other)
yang merupakan.
Sekarang, untuk menghitung nilai 4 dan 6, sangat mudah bahwa t3 yang memiliki referensi dan inisialisasi Test memanggil
equals()
metode dengan parameter sebagai referensi Objek dan merupakanBAIK!
sumber