Saya memiliki Daftar yang dinyatakan seperti ini:
List<? extends Number> foo3 = new ArrayList<Integer>();
Saya mencoba menambahkan 3 ke foo3. Namun saya mendapatkan pesan kesalahan seperti ini:
The method add(capture#1-of ? extends Number) in the type List<capture#1-of ?
extends Number> is not applicable for the arguments (ExtendsNumber)
List<? extends Number>
tidak berarti "daftar objek dari berbagai jenis, yang semuanya meluasNumber
". Ini berarti "daftar objek dari tipe tunggal yang memanjangNumber
".Jawaban:
Maaf, tetapi Anda tidak bisa.
Deklarasi wildcard
List<? extends Number> foo3
berarti bahwa variabelfoo3
dapat menyimpan nilai apa pun dari keluarga jenis (bukan nilai apa pun dari jenis tertentu). Ini berarti bahwa semua ini adalah penugasan legal:Jadi, mengingat ini, jenis objek apa yang bisa Anda tambahkan
List foo3
yang akan sah setelah salah satu dariArrayList
penugasan di atas :Integer
karenafoo3
bisa menunjuk sebuahList<Double>
.Double
karenafoo3
bisa menunjuk pada aList<Integer>
.Number
karenafoo3
bisa menunjuk pada aList<Integer>
.Anda tidak dapat menambahkan objek apa pun
List<? extends T>
karena Anda tidak dapat menjamin jenis apaList
yang benar-benar mengarah, sehingga Anda tidak dapat menjamin bahwa objek tersebut diizinkanList
. Satu-satunya "jaminan" adalah bahwa Anda hanya dapat membacanya dan Anda akan mendapatkanT
atau subkelas dariT
.Logika balik berlaku untuk
super
, misalnyaList<? super T>
. Ini legal:Anda tidak dapat membaca jenis T tertentu (misalnya
Number
)List<? super T>
karena Anda tidak dapat menjamin jenis apaList
yang benar-benar mengarah. Satu-satunya "jaminan" yang Anda miliki adalah Anda dapat menambahkan nilai tipeT
(atau subkelas apa punT
) tanpa melanggar integritas daftar yang ditunjuk.Contoh sempurna dari ini adalah tanda tangan untuk
Collections.copy()
:Perhatikan bagaimana
src
deklarasi daftar digunakanextends
untuk memungkinkan saya untuk melewati Daftar apa pun dari keluarga tipe Daftar terkait dan masih menjamin itu akan menghasilkan nilai tipe T atau subkelas dari T. Tapi Anda tidak dapat menambahkan kesrc
daftar.The
dest
penggunaan daftar deklarasisuper
untuk mengizinkan saya untuk lulus Daftar apapun dari keluarga jenis Daftar terkait dan masih menjamin aku bisa menulis nilai dari jenis tertentu T ke daftar itu. Tetapi tidak dapat dijamin untuk membaca nilai-nilai tipe T tertentu jika saya membaca dari daftar.Jadi sekarang, berkat wildcard generik, saya dapat melakukan semua panggilan ini dengan metode tunggal:
Pertimbangkan kode yang membingungkan dan sangat luas ini untuk melatih otak Anda. Baris yang dikomentari adalah ilegal dan alasan mengapa dinyatakan pada ujung kanan garis (perlu menggulir untuk melihat beberapa di antaranya):
sumber
src
List
penggunaan argumenextends
untuk membaca dari daftar src, sedangkan yangdest
List
menggunakan argumensuper
untuk menulis ke daftar dest. Ini memungkinkan satu metode yang dapat menyalin dariList<Integer>
atauList<Double>
keList<Number>
atauList<Object>
.or subclass of T
benar. Sebagai contoh, saya tidak dapat menambahkan sebuahObject
(superclassNumber
) keList<? super Number> foo3
karenafoo3
mungkin telah ditetapkan sebagai:List<? super Number> foo3 = new ArrayList<Number>
(yang dapat berisi hanyaNumber
atau subkelas dariNumber
).<? super Number>
mengacu pada jenisList<>
s yang dapat ditugaskanfoo3
- bukan jenis hal yang dapat ditambahkan / dibaca dari itu. Jenis-jenis hal yang dapat ditambahkan / dihapusfoo3
harus berupa hal-hal yang dapat ditambahkan / dihapus dari segala jenisList<>
yang dapat ditugaskanfoo3
.Anda tidak bisa (tanpa gips yang tidak aman). Anda hanya dapat membaca dari mereka.
Masalahnya adalah Anda tidak tahu daftar itu. Itu bisa berupa daftar subkelas Number, jadi ketika Anda mencoba memasukkan elemen ke dalamnya, Anda tidak tahu bahwa elemen tersebut benar-benar cocok dengan daftar.
Misalnya Daftar mungkin daftar
Byte
s, jadi itu akan menjadi kesalahan untuk memasukkannyaFloat
ke dalamnya.sumber
"Daftar '<'? Extends Number> sebenarnya adalah wildcard batas atas!
Wildcard batas atas mengatakan bahwa setiap kelas yang memperluas Angka atau Angka itu sendiri dapat digunakan sebagai tipe parameter formal: Masalahnya berasal dari fakta bahwa Java tidak tahu apa tipe Daftar sebenarnya. Itu harus menjadi tipe EXACT dan UNIK. Saya harap ini membantu :)
sumber
Itu membingungkan saya walaupun saya membaca jawaban di sini, sampai saya menemukan komentar oleh Pavel Minaev:
Setelah ini saya bisa mengerti penjelasan BertF yang luar biasa. Daftar <? extends Number> means? bisa dari jenis apa saja yang memperpanjang Nomor (Integer, Double, dll) dan tidak diklarifikasi dalam deklarasi (Daftar <? extends Number> daftar) yang mana dari mereka itu, jadi ketika Anda ingin menggunakan metode add itu tidak diketahui jika inputnya adalah dari jenis yang sama atau tidak; apa jenisnya?
Jadi elemen Daftar <? extends Number> hanya dapat diatur saat membuat.
Perhatikan juga ini: Ketika kita menggunakan templat, kita memberi tahu kompiler jenis apa yang kita mainkan. T misalnya memegang jenis itu untuk kita, tetapi tidak ?melakukan hal yang sama
Saya harus mengatakan .. Ini adalah salah satu yang kotor untuk dijelaskan / dipelajari
sumber
Anda bisa melakukan ini sebagai gantinya:
sumber
Anda dapat memperdayainya dengan membuat referensi ke Daftar dengan tipe yang berbeda.
(Ini adalah "pemain tidak aman" yang disebutkan oleh sepp2k.)
Karena
untypedList
,superclassedList
dantrulyclassedList
hanya referensilist
, Anda masih akan menambahkan elemen ke ArrayList asli.Anda sebenarnya tidak perlu menggunakan
(List<?>)
dalam contoh di atas, tetapi Anda mungkin membutuhkannya dalam kode Anda, tergantung pada jenislist
Anda diberikan.Perhatikan bahwa menggunakan
?
akan memberi Anda peringatan kompiler, sampai Anda menempatkan ini di atas fungsi Anda:sumber
tempat memperluas daftar dari 'Objek', Anda dapat menggunakan list.add dan ketika ingin menggunakan list.get hanya perlu melemparkan Objek ke Objek Anda;
sumber