Java Generics - lwn

1. Gambaran keseluruhan

Dalam tutorial ringkas ini, kita akan melihat persamaan dan perbezaan antara dan dalam Java Generics .

Walau bagaimanapun, kerana ini adalah topik lanjutan, sangat mustahak untuk mendapatkan pemahaman asas mengenai topik ini sebelum kita menyelidiki inti masalah ini.

2. Latar Belakang Generik

Generik diperkenalkan di JDK 5 untuk menghilangkan kesilapan masa kompilasi dan memperkuat keselamatan jenis. Keselamatan jenis tambahan ini menghilangkan pemutus dalam beberapa kes penggunaan dan memberi kuasa kepada pengaturcara untuk menulis algoritma generik, yang kedua-duanya boleh menyebabkan kod yang lebih mudah dibaca.

Sebagai contoh, pra-JDK 5, kita harus bekerjasama dengan unsur-unsur senarai menggunakan casting. Ini, seterusnya, membuat ralat kelas runtime tertentu:

List aList = new ArrayList(); aList.add(new Integer(1)); aList.add("a_string"); for (int i = 0; i < aList.size(); i++) { Integer x = (Integer) aList.get(i); }

Sekarang, kod ini mempunyai dua masalah yang ingin kita atasi:

  • Kami memerlukan pemeran eksplisit untuk mengekstrak nilai dari aList - jenisnya bergantung pada jenis pemboleh ubah di sebelah kiri - Integer dalam kes ini
  • Kami akan mendapat ralat runtime pada lelaran kedua ketika kami cuba menghantar a_string ke Integer

Generik mengisi peranan untuk kita:

List iList = new ArrayList(); iList.add(1); iList.add("a_string"); // compile time error for (int i = 0; i < iList.size(); i++) { int x = iList.get(i); } 

Pengkompilasi akan memberitahu kita bahawa tidak mungkin untuk menambahkan a_string ke Senarai jenis Integer , yang lebih baik daripada mengetahui pada waktu runtime.

Lebih-lebih lagi, pemutus eksplisit tidak diperlukan kerana penyusun sudah mengetahui bahawa iList memegang Integer s. Selain itu, kerana keajaiban membuka kotak, kita tidak memerlukan jenis Integer , bentuk primitifnya sudah cukup.

3. Wildcard dalam Generik

Tanda tanya, atau wildcard, digunakan dalam generik untuk mewakili jenis yang tidak diketahui. Ia boleh mempunyai tiga bentuk:

  • Wildcard Tidak Terikat : Senarai mewakili senarai jenis yang tidak diketahui
  • Wildcound Upper Bounded : List mewakili senarai Number atau subjenisnya seperti Integer dan Double
  • Wildcound Wild Bounded : List mewakili senarai Integer atau nombor dan Objek super-jenisnya

Sekarang, kerana Objek adalah jenis super yang melekat dari semua jenis di Jawa, kita akan tergoda untuk berfikir bahawa objek tersebut juga dapat mewakili jenis yang tidak diketahui. Dengan kata lain, List dan List dapat memenuhi tujuan yang sama. Tetapi mereka tidak.

Mari kita pertimbangkan dua kaedah ini:

public static void printListObject(List list) {     for (Object element : list) {         System.out.print(element + " ");     }         }     public static void printListWildCard(List list) {     for (Object element: list) {         System.out.print(element + " ");     }     } 

Dengan senarai Integer s, katakan:

List li = Arrays.asList(1, 2, 3);

printListObject (li) tidak akan menyusun, dan kami akan mendapat ralat ini:

The method printListObject(List) is not applicable for the arguments (List)

Manakala printListWildCard (li) akan menyusun dan akan mengeluarkan 1 2 3 ke konsol.

4. dan - Persamaan

Dalam contoh di atas, jika kita menukar kaedah tandatangan untuk printListWildCard kepada:

public static void printListWildCard(List list)

Ia akan berfungsi dengan cara yang sama seperti printListWildCard (Daftar senarai) . Ini disebabkan oleh fakta bahawa Objek adalah supertype dari semua objek Java, dan pada dasarnya semuanya meluas Objek . Jadi, Senarai daripada Integer s mendapat diproses juga.

Ringkasnya, ini bermaksud ? dan ? memanjangkan Objek adalah sinonim dalam contoh ini .

Walaupun dalam kebanyakan kes itu berlaku, tetapi ada beberapa perbezaan juga . Mari lihat mereka di bahagian seterusnya.

5. dan - perbezaan

Jenis yang boleh disahkan adalah jenis yang jenisnya tidak dipadamkan pada masa penyusunan. Dengan kata lain, perwakilan waktu proses jenis yang tidak dapat disahkan tidak akan mempunyai maklumat yang lebih sedikit daripada rakan masa-masa kompilasinya, kerana sebahagiannya akan dihapus.

Sebagai peraturan umum, jenis parameter tidak dapat disahkan semula. Ini bermaksud Senarai dan Peta tidak dapat disahkan semula. Pengkompilasi masing-masing menghapus jenisnya dan memperlakukannya sebagai Senarai dan Peta .

Satu-satunya pengecualian untuk peraturan ini adalah jenis wildcard tanpa had. Ini bermaksud Senarai dan Peta boleh disahkan semula .

Sebaliknya, Senarai tidak boleh disahkan semula . Walaupun halus, ini adalah perbezaan yang ketara.

Jenis yang tidak dapat disahkan tidak boleh digunakan dalam situasi tertentu seperti dalam contoh operator atau sebagai elemen array.

Jadi, jika kita menulis:

List someList = new ArrayList(); boolean instanceTest = someList instanceof List

Kod ini menyusun dan instanceTest adalah benar .

Tetapi, jika kita menggunakan contoh operator di Senarai :

List anotherList = new ArrayList(); boolean instanceTest = anotherList instanceof List;

maka baris 2 tidak menyusun.

Begitu juga, dalam coretan di bawah, baris 1 menyusun, tetapi baris 2 tidak:

List[] arrayOfList = new List[1]; List[] arrayOfAnotherList = new List[1]

6. Kesimpulannya

Dalam tutorial ringkas ini, kami melihat persamaan dan perbezaan dalam dan .

Walaupun kebanyakannya serupa, terdapat perbezaan yang halus antara keduanya dari segi pengesahan atau tidak.