public class Animal {
public void eat() {}
}
public class Dog extends Animal {
public void eat() {}
public void main(String[] args) {
Animal animal = new Animal();
Dog dog = (Dog) animal;
}
}
Tugas Dog dog = (Dog) animal;
tidak menghasilkan kesalahan kompilasi, tetapi pada saat runtime ia menghasilkan a ClassCastException
. Mengapa kompiler tidak dapat mendeteksi kesalahan ini?
java
casting
classcastexception
saravanan
sumber
sumber
Jawaban:
Dengan menggunakan gips Anda pada dasarnya mengatakan kepada kompiler "percayalah padaku. Saya seorang profesional, saya tahu apa yang saya lakukan dan saya tahu bahwa meskipun Anda tidak dapat menjaminnya, saya memberi tahu Anda bahwa
animal
variabel ini pasti akan menjadi seekor anjing. "Karena hewan itu sebenarnya bukan anjing (itu hewan, Anda bisa melakukannya
Animal animal = new Dog();
dan itu akan menjadi anjing) VM melempar pengecualian saat runtime karena Anda telah melanggar kepercayaan itu (Anda mengatakan kepada kompiler semuanya akan baik-baik saja dan itu tidak!)Kompiler sedikit lebih pintar daripada hanya menerima secara membabi buta segalanya, jika Anda mencoba dan melemparkan objek dalam hierarki pewarisan yang berbeda (misalnya, melempar Anjing ke Tali), maka kompiler akan mengembalikannya kepada Anda karena ia tahu bahwa itu tidak akan pernah bisa berfungsi.
Karena pada dasarnya Anda hanya menghentikan kompiler agar tidak mengeluh, setiap kali Anda memberikannya penting untuk memeriksa bahwa Anda tidak akan menyebabkan
ClassCastException
dengan menggunakaninstanceof
dalam pernyataan if (atau sesuatu untuk efek itu.)sumber
Dog
tidak diperpanjang dariAnimal
!Karena secara teori
Animal animal
bisa menjadi anjing:Umumnya, downcasting bukanlah ide yang baik. Anda harus menghindarinya. Jika Anda menggunakannya, Anda sebaiknya menyertakan cek:
sumber
Untuk menghindari ClassCastException semacam ini, jika Anda memiliki:
Anda dapat mendefinisikan konstruktor dalam B yang mengambil objek A. Dengan cara ini kita bisa melakukan "pemeran" misalnya:
sumber
Menguraikan jawaban yang diberikan oleh Michael Berry.
Dog d = (Dog)Animal; //Compiles but fails at runtime
Di sini Anda mengatakan kepada kompiler "Percayalah. Saya tahu
d
benar-benar mengacu padaDog
objek" meskipun tidak. Ingat kompiler dipaksa untuk mempercayai kami ketika kami melakukan downcast .Jadi ketika JVM pada saat runtime mengetahui bahwa
Dog d
sebenarnya mengacu padaAnimal
dan bukanDog
objek yang dikatakannya. Hei ... kau berbohong ke kompiler dan membuang banyak lemakClassCastException
.Jadi, jika Anda downcasting Anda harus menggunakan
instanceof
tes untuk menghindari mengacaukan.if (animal instanceof Dog) { Dog dog = (Dog) animal; }
Sekarang sebuah pertanyaan muncul di benak kami. Mengapa kompiler itu membiarkan yang tertunduk ketika akhirnya akan membuang
java.lang.ClassCastException
?Jawabannya adalah yang dapat dilakukan oleh semua kompiler adalah memverifikasi bahwa kedua jenis berada di pohon warisan yang sama, jadi tergantung pada kode apa pun yang mungkin datang sebelum downcast, mungkin
animal
jenisnyadog
.Pertimbangkan snipet kode berikut:
Namun, jika kompiler yakin bahwa para pemain tidak akan bekerja, kompilasi akan gagal. IE Jika Anda mencoba untuk melemparkan objek dalam hierarki warisan yang berbeda
String s = (String)d; // ERROR : cannot cast for Dog to String
Dog d = new Dog(); Animal animal1 = d; // Works fine with no explicit cast Animal animal2 = (Animal) d; // Works fine with n explicit cast
Kedua hal yang disebutkan di atas akan bekerja dengan baik tanpa kecuali karena Anjing IS-A Animal, anithing an Animal dapat melakukan, seekor anjing dapat melakukannya. Tetapi itu tidak benar vica-versa.
sumber
Kode menghasilkan kesalahan kompilasi karena tipe instance Anda adalah Hewan:
Downcasting tidak diperbolehkan di Jawa karena beberapa alasan. Lihat di sini untuk detailnya.
sumber
Seperti yang dijelaskan, itu tidak mungkin. Jika Anda ingin menggunakan metode subclass, evaluasi kemungkinan untuk menambahkan metode ke superclass (mungkin kosong) dan panggilan dari subclass untuk mendapatkan perilaku yang Anda inginkan (subclass) berkat polimorfisme. Jadi, ketika Anda menelepon d.method () panggilan akan berhasil tanpa casting, tetapi jika objeknya bukan anjing, tidak akan ada masalah
sumber
Untuk mengembangkan jawaban @Caumons:
Sekarang lihat solusi ini.
Sekarang kami menguji aplikasi:
Dan inilah hasilnya:
Sekarang Anda dapat dengan mudah menambahkan bidang baru ke kelas ayah tanpa khawatir kode anak Anda akan rusak;
sumber