Saya ragu ada perbedaan. Saya kira itu hanya nama untuk parameter tipe itu. Dan apakah yang terakhir bahkan valid?
CodesInChaos
Jawaban:
231
Yah tidak ada perbedaan antara dua yang pertama - mereka hanya menggunakan nama yang berbeda untuk parameter tipe ( Eatau T).
Yang ketiga bukan deklarasi yang valid - ?digunakan sebagai wildcard yang digunakan saat memberikan argumen tipe , mis. List<?> foo = ...Sarana yang foomerujuk ke daftar jenis tertentu, tapi kami tidak tahu apa.
Semua ini adalah obat generik , yang merupakan topik yang cukup besar. Anda mungkin ingin mempelajarinya melalui sumber daya berikut, walaupun tentu saja ada lebih banyak tersedia:
Sepertinya tautan ke PDF rusak. Saya telah menemukan apa yang tampak sebagai salinan di sini , tetapi saya tidak dapat memastikan 100% karena saya tidak tahu seperti apa aslinya.
John
2
@ John: Yup, itu dia. Akan mengedit tautan, apakah yang itu atau yang Oracle ...
Jon Skeet
Apakah ada selain T, E dan? digunakan dalam obat generik? Jika demikian, apakah mereka dan apa artinya?
sofs1
1
@ sofs1: Tidak ada yang istimewa Tdan E- mereka hanya pengidentifikasi. Anda bisa menulis KeyValuePair<K, V>misalnya. ?memiliki makna khusus.
Jon Skeet
215
Itu lebih banyak konvensi daripada yang lainnya.
T dimaksudkan untuk menjadi Tipe
Edimaksudkan untuk menjadi Elemen ( List<E>: daftar Elemen)
Kadalah Kunci (dalam a Map<K,V>)
V adalah Nilai (sebagai nilai balik atau nilai yang dipetakan)
Mereka sepenuhnya dipertukarkan (konflik dalam deklarasi yang sama meskipun).
Huruf antara <> hanyalah sebuah nama. Apa yang Anda gambarkan dalam jawaban Anda hanyalah konvensi. Itu bahkan tidak harus menjadi huruf tunggal, huruf besar; Anda dapat menggunakan nama apa pun yang Anda suka, sama seperti Anda bisa memberikan kelas, variabel dll nama apa pun yang Anda suka.
Anda tidak menjelaskan pada tanda tanya. Diturunkan.
shinzou
129
Jawaban sebelumnya menjelaskan parameter tipe (T, E, dll.), Tetapi jangan menjelaskan wildcard, "?", Atau perbedaan di antara mereka, jadi saya akan membahasnya.
Pertama, untuk memperjelas: wildcard dan parameter type tidak sama. Di mana parameter tipe mendefinisikan semacam variabel (misalnya, T) yang mewakili tipe untuk cakupan, wildcard tidak: wildcard hanya mendefinisikan sekumpulan tipe yang diijinkan yang dapat Anda gunakan untuk tipe generik. Tanpa ada pembatas ( extendsatau super), wildcard berarti "gunakan jenis apa pun di sini".
Wildcard selalu datang di antara kurung sudut, dan itu hanya memiliki makna dalam konteks tipe generik:
publicvoid foo(List<?> listOfAnyType){...}// pass a List of any type
tidak pernah
public<?>? bar(? someType){...}// error. Must use type params here
Semakin membingungkan di mana mereka tumpang tindih. Sebagai contoh:
List<T> fooList;// A list which will be of type T, when T is chosen.// Requires T was defined above in this scopeList<?> barList;// A list of some type, decided elsewhere. You can do// this anywhere, no T required.
Ada banyak tumpang tindih dalam apa yang mungkin dengan definisi metode. Berikut ini adalah, secara fungsional, identik:
Jadi, jika ada tumpang tindih, mengapa menggunakan yang satu atau yang lain? Kadang-kadang, itu hanya gaya: beberapa orang mengatakan bahwa jika Anda tidak memerlukan param tipe, Anda harus menggunakan wildcard hanya untuk membuat kode lebih sederhana / lebih mudah dibaca. Satu perbedaan utama yang saya jelaskan di atas: tipe params mendefinisikan variabel tipe (misalnya, T) yang dapat Anda gunakan di tempat lain dalam ruang lingkup; wildcard tidak. Kalau tidak, ada dua perbedaan besar antara tipe params dan wildcard:
Tipe params dapat memiliki beberapa kelas pembatas; wildcard tidak dapat:
Wildcard dapat memiliki batas bawah; jenis params tidak dapat:
publicvoid bar(List<?superInteger> list){...}
Di atas List<? super Integer>didefinisikan Integersebagai batas bawah pada wildcard, artinya tipe Daftar harus Integer atau tipe super Integer. Pembatasan tipe generik melampaui apa yang ingin saya bahas secara rinci. Singkatnya, ini memungkinkan Anda untuk menentukan jenis tipe generik. Hal ini memungkinkan untuk mengobati obat generik secara polimorfik. Misalnya dengan:
publicvoid foo(List<?extendsNumber> numbers){...}
Anda dapat lulus List<Integer>, List<Float>, List<Byte>, dll untuk numbers. Tanpa batasan jenis, ini tidak akan berhasil - itu hanya bagaimana generik.
Akhirnya, inilah definisi metode yang menggunakan wildcard untuk melakukan sesuatu yang saya pikir Anda tidak bisa melakukan cara lain:
numberSuperdapat berupa Daftar Nomor atau supertipe Nomor (misalnya, List<Object>), dan elemharus Nomor atau subtipe apa pun. Dengan semua lompatan, kompiler dapat yakin bahwa itu .add()adalah typesafe.
"public void foo (Daftar nomor <? extends>>) {...}" haruskah "extends" menjadi "super"?
1a1a11a
1
Maksud dari contoh itu adalah untuk menunjukkan tanda tangan yang secara polimorfis mendukung Daftar Nomor dan sub-jenis Nomor. Untuk ini, Anda menggunakan "extends". Yaitu, "berikan saya Daftar Angka atau apa pun yang meluas Angka" (Daftar <Integer>, Daftar <Float>, apa pun). Metode seperti ini mungkin kemudian beralih melalui daftar dan, untuk setiap elemen, "e", jalankan, misalnya, e.floatValue (). Tidak masalah apa pun sub-tipe (ekstensi) Angka yang Anda lewati - Anda akan selalu dapat ".FloatValue ()", karena .floatValue () adalah metode Number.
Hawkeye Parker
Pada contoh terakhir Anda, "Daftar <? Nomor super>" hanya bisa menjadi "Daftar <Number>" karena metode ini tidak memungkinkan hal lain yang lebih umum.
jessarah
@ jessarah nggak. Mungkin contoh saya tidak jelas, tetapi saya menyebutkan dalam contoh bahwa adder () dapat mengambil Daftar <Object> (Objek adalah superclass of Number). Jika Anda ingin dapat melakukan ini, ia harus memiliki tanda tangan "Daftar <? Nomor super>". Itulah titik "super" di sini.
Hawkeye Parker
2
Jawaban ini sangat baik dalam menjelaskan perbedaan antara wildcard dan parameter tipe, harus ada satu pertanyaan khusus dengan jawaban ini. Saya semakin mendalam tentang obat-obatan generik akhir-akhir ini dan jawaban ini banyak membantu saya dalam menyatukan berbagai hal, banyak informasi singkat, terima kasih!
Testo Testini
27
Variabel tipe, <T>, bisa berupa tipe non-primitif apa pun yang Anda tentukan: tipe kelas apa pun, tipe antarmuka apa pun, tipe array apa pun, atau bahkan variabel tipe lain.
Nama parameter tipe yang paling umum digunakan adalah:
E-Element (digunakan secara luas oleh Java Collections Framework)
K - Key
N - Nomor
Tipe T
V - Nilai
Di Java 7 diizinkan untuk instantiate seperti ini:
Jawaban:
Yah tidak ada perbedaan antara dua yang pertama - mereka hanya menggunakan nama yang berbeda untuk parameter tipe (
E
atauT
).Yang ketiga bukan deklarasi yang valid -
?
digunakan sebagai wildcard yang digunakan saat memberikan argumen tipe , mis.List<?> foo = ...
Sarana yangfoo
merujuk ke daftar jenis tertentu, tapi kami tidak tahu apa.Semua ini adalah obat generik , yang merupakan topik yang cukup besar. Anda mungkin ingin mempelajarinya melalui sumber daya berikut, walaupun tentu saja ada lebih banyak tersedia:
sumber
T
danE
- mereka hanya pengidentifikasi. Anda bisa menulisKeyValuePair<K, V>
misalnya.?
memiliki makna khusus.Itu lebih banyak konvensi daripada yang lainnya.
T
dimaksudkan untuk menjadi TipeE
dimaksudkan untuk menjadi Elemen (List<E>
: daftar Elemen)K
adalah Kunci (dalam aMap<K,V>
)V
adalah Nilai (sebagai nilai balik atau nilai yang dipetakan)Mereka sepenuhnya dipertukarkan (konflik dalam deklarasi yang sama meskipun).
sumber
Jawaban sebelumnya menjelaskan parameter tipe (T, E, dll.), Tetapi jangan menjelaskan wildcard, "?", Atau perbedaan di antara mereka, jadi saya akan membahasnya.
Pertama, untuk memperjelas: wildcard dan parameter type tidak sama. Di mana parameter tipe mendefinisikan semacam variabel (misalnya, T) yang mewakili tipe untuk cakupan, wildcard tidak: wildcard hanya mendefinisikan sekumpulan tipe yang diijinkan yang dapat Anda gunakan untuk tipe generik. Tanpa ada pembatas (
extends
atausuper
), wildcard berarti "gunakan jenis apa pun di sini".Wildcard selalu datang di antara kurung sudut, dan itu hanya memiliki makna dalam konteks tipe generik:
tidak pernah
atau
Semakin membingungkan di mana mereka tumpang tindih. Sebagai contoh:
Ada banyak tumpang tindih dalam apa yang mungkin dengan definisi metode. Berikut ini adalah, secara fungsional, identik:
Jadi, jika ada tumpang tindih, mengapa menggunakan yang satu atau yang lain? Kadang-kadang, itu hanya gaya: beberapa orang mengatakan bahwa jika Anda tidak memerlukan param tipe, Anda harus menggunakan wildcard hanya untuk membuat kode lebih sederhana / lebih mudah dibaca. Satu perbedaan utama yang saya jelaskan di atas: tipe params mendefinisikan variabel tipe (misalnya, T) yang dapat Anda gunakan di tempat lain dalam ruang lingkup; wildcard tidak. Kalau tidak, ada dua perbedaan besar antara tipe params dan wildcard:
Tipe params dapat memiliki beberapa kelas pembatas; wildcard tidak dapat:
Wildcard dapat memiliki batas bawah; jenis params tidak dapat:
Di atas
List<? super Integer>
didefinisikanInteger
sebagai batas bawah pada wildcard, artinya tipe Daftar harus Integer atau tipe super Integer. Pembatasan tipe generik melampaui apa yang ingin saya bahas secara rinci. Singkatnya, ini memungkinkan Anda untuk menentukan jenis tipe generik. Hal ini memungkinkan untuk mengobati obat generik secara polimorfik. Misalnya dengan:Anda dapat lulus
List<Integer>
,List<Float>
,List<Byte>
, dll untuknumbers
. Tanpa batasan jenis, ini tidak akan berhasil - itu hanya bagaimana generik.Akhirnya, inilah definisi metode yang menggunakan wildcard untuk melakukan sesuatu yang saya pikir Anda tidak bisa melakukan cara lain:
numberSuper
dapat berupa Daftar Nomor atau supertipe Nomor (misalnya,List<Object>
), danelem
harus Nomor atau subtipe apa pun. Dengan semua lompatan, kompiler dapat yakin bahwa itu.add()
adalah typesafe.sumber
Variabel tipe, <T>, bisa berupa tipe non-primitif apa pun yang Anda tentukan: tipe kelas apa pun, tipe antarmuka apa pun, tipe array apa pun, atau bahkan variabel tipe lain.
Nama parameter tipe yang paling umum digunakan adalah:
Di Java 7 diizinkan untuk instantiate seperti ini:
sumber
Nama parameter tipe yang paling umum digunakan adalah:
Anda akan melihat nama-nama ini digunakan di seluruh Java SE API
sumber
kompiler akan membuat tangkapan untuk setiap wildcard (misalnya, tanda tanya di Daftar) ketika membuat fungsi seperti:
Namun tipe generik seperti V akan baik-baik saja dan menjadikannya metode generik :
sumber