Misalkan saya memiliki hierarki kelas ini ...
public abstract class Animal {
public abstract void eat();
public abstract void talk();
}
class Dog extends Animal {
@Override
public void eat() {
}
@Override
public void talk() {
}
}
class Cat extends Animal {
@Override
public void eat() {
}
@Override
public void talk() {
}
}
Dan kemudian saya ....
public static <T extends Animal> void addAnimal(T animal) {
animal.eat();
animal.talk();
}
public static void addAnimalPoly(Animal animal) {
animal.eat();
animal.talk();
}
Apa perbedaannya ketika menggunakan parameter tipe terbatas atau polimorfisme?
Dan kapan harus menggunakan satu atau yang lain?
java
polymorphism
generics
HugoMelo
sumber
sumber
addAnimals(List<Animal>)
dan menambahkan Daftar Kucing!Jawaban:
Kedua contoh ini setara, dan pada kenyataannya akan dikompilasi dengan bytecode yang sama.
Ada dua cara yang menambahkan tipe generik terbatas ke metode seperti pada contoh pertama Anda akan melakukan apa saja.
Melewati parameter tipe ke tipe lain
Kedua tanda tangan metode ini pada akhirnya sama dengan kode byte, tetapi kompiler memberlakukan keamanan tipe:
public static <T extends Animal> void addAnimals(Collection<T> animals)
public static void addAnimals(Collection<Animal> animals)
Dalam kasus pertama, hanya
Collection
(atau subtipe) dariAnimal
yang diizinkan. Dalam kasus kedua, aCollection
(atau subtipe) dengan tipe generikAnimal
atau subtipe diperbolehkan.Misalnya, yang berikut diperbolehkan dalam metode pertama tetapi tidak yang kedua:
Alasannya adalah bahwa yang kedua hanya memungkinkan koleksi hewan, sedangkan yang pertama memungkinkan koleksi benda apa pun yang ditugaskan untuk hewan (yaitu subtipe). Perhatikan bahwa jika daftar ini adalah daftar hewan yang mengandung kucing, metode mana pun akan menerimanya: masalahnya adalah spesifikasi umum koleksi, bukan apa yang sebenarnya dikandungnya.
Mengembalikan benda
Waktu lain yang penting adalah dengan mengembalikan objek. Mari kita asumsikan ada metode berikut:
Anda dapat melakukan hal berikut dengan itu:
Meskipun ini adalah contoh yang dibuat-buat, ada beberapa kasus yang masuk akal. Tanpa obat generik, metode ini harus kembali
Animal
dan Anda perlu menambahkan tipe casting untuk membuatnya berfungsi (yang merupakan kompiler yang menambahkan kode byte di belakang layar).sumber
Gunakan obat generik alih-alih downcasting. "Downcasting" buruk, beralih dari tipe yang lebih umum ke yang lebih spesifik:
... Anda mempercayai itu
a
adalah kucing, tetapi kompiler tidak dapat menjamin hal itu. Mungkin berubah menjadi anjing saat runtime.Di sinilah Anda akan menggunakan obat generik:
Sekarang Anda dapat menentukan bahwa Anda menginginkan pemburu kucing:
Sekarang kompiler dapat menjamin bahwa hunterC hanya akan menangkap kucing, dan hunterD hanya akan menangkap anjing.
Jadi gunakan polimorfisme biasa jika Anda hanya ingin menangani kelas-kelas tertentu sebagai tipe dasarnya. Mengabaikan adalah hal yang baik. Tetapi jika Anda berada dalam situasi di mana Anda perlu menangani kelas-kelas tertentu sebagai tipe mereka sendiri, gunakan generik secara umum.
Atau, sungguh, jika Anda harus tertunduk maka gunakan obat generik.
EDIT: kasus yang lebih umum adalah ketika Anda ingin menunda keputusan jenis apa yang harus ditangani. Jadi tipe menjadi parameter, dan juga nilainya.
Katakanlah saya ingin kelas Kebun Binatang saya menangani Kucing atau Spons. Saya tidak memiliki kelas super umum. Tapi saya masih bisa menggunakan:
sejauh mana Anda mengunci itu tergantung pada apa yang Anda coba lakukan;)
sumber
Pertanyaan ini sudah tua, tetapi faktor penting untuk dipertimbangkan tampaknya telah ditinggalkan mengenai kapan harus menggunakan parameter tipe polimorfisme vs terikat. Faktor ini mungkin sedikit bersinggungan dengan contoh yang diberikan dalam pertanyaan tetapi, saya merasa, sangat relevan dengan yang lebih umum "Kapan menggunakan parameter tipe polimorfisme vs terikat?"
TL; DR
Jika Anda pernah menemukan diri Anda memindahkan kode dari subkelas ke kelas dasar melawan penilaian Anda yang lebih baik, karena ketidakmampuan mengaksesnya dengan cara polimorfik, parameter tipe terikat dapat menjadi solusi potensial.
Jawaban Lengkap
Parameter tipe terikat dapat mengekspos metode subkelas yang tidak diwariskan untuk variabel anggota yang diwarisi. Polimorfisme tidak bisa
Untuk menguraikan dengan memperluas contoh Anda:
Jika kelas abstrak AnimalOwner didefinisikan memiliki
protected Animal pet;
dan memilih polimorfisme, kompiler akan melakukan kesalahan padapet.scratchBelly();
baris, memberi tahu Anda bahwa metode ini tidak ditentukan untuk Hewan.sumber
Dalam contoh Anda, Anda tidak (dan tidak seharusnya) menggunakan tipe terikat. Hanya gunakan parameter tipe terbatas ketika Anda harus , karena mereka lebih membingungkan untuk dipahami.
Berikut adalah beberapa situasi di mana Anda akan menggunakan parameter tipe terbatas:
Parameter koleksi
maka kamu bisa menelepon
zoo.add(dogs)
akan gagal untuk mengkompilasi tanpa<? extends Animal>
, karena obat generik tidak kovarian.Subklasifikasi
untuk membatasi jenis subclass dapat menyediakan.
Anda juga dapat menggunakan beberapa batasan
<T extends A1 & A2 & A3>
untuk memastikan suatu jenis adalah subtipe dari semua jenis dalam daftar.sumber