Membuat Array Generik di Jawa

1. Pengenalan

Kami mungkin ingin menggunakan tatasusunan sebagai sebahagian daripada kelas atau fungsi yang menyokong generik. Oleh kerana cara Java menangani generik, ini sukar.

Dalam tutorial ini, kita akan memahami cabaran penggunaan generik dengan tatasusunan. Kemudian, kami akan membuat contoh susunan generik.

Kami juga akan melihat di mana Java API telah menyelesaikan masalah yang serupa.

2. Pertimbangan Semasa Menggunakan Susunan Generik

Perbezaan penting antara tatasusunan dan generik adalah bagaimana mereka melaksanakan pemeriksaan jenis. Secara khusus, tatasusunan menyimpan dan memeriksa maklumat jenis semasa waktu berjalan. Generik, bagaimanapun, memeriksa kesilapan jenis pada waktu kompilasi dan tidak mempunyai maklumat jenis pada waktu runtime.

Sintaks Java menunjukkan bahawa kita mungkin dapat membuat susunan generik baru:

T[] elements = new T[size];

Tetapi, jika kami mencuba ini, kami akan mendapat ralat kompilasi.

Untuk memahami sebabnya, mari pertimbangkan perkara berikut:

public  T[] getArray(int size) { T[] genericArray = new T[size]; // suppose this is allowed return genericArray; }

Sebagai jenis generik T yang tidak terikat menyelesaikan Objek, kaedah kami pada waktu berjalan adalah:

public Object[] getArray(int size) { Object[] genericArray = new Object[size]; return genericArray; }

Kemudian, jika kita memanggil kaedah kita dan menyimpan hasilnya dalam array String :

String[] myArray = getArray(5);

Kodnya akan dikompilasi dengan baik tetapi gagal pada waktu operasi dengan ClassCastException . Ini kerana kami baru saja menetapkan Objek [] untuk sebutan String [] . Secara khusus, pemeran tersirat oleh penyusun akan gagal menukar Objek [] ke String jenis kami yang diperlukan [] .

Walaupun kita tidak dapat menginisialisasi susunan generik secara langsung, masih mungkin untuk mencapai operasi yang setara jika jenis maklumat yang tepat diberikan oleh kod panggilan.

3. Membuat Susunan Generik

Sebagai contoh, mari kita pertimbangkan struktur data tumpukan terikat MyStack , di mana kapasiti tetap pada ukuran tertentu. Juga, kerana kami ingin timbunan berfungsi dengan jenis apa pun, pilihan pelaksanaan yang wajar adalah susunan generik.

Pertama, mari buat medan untuk menyimpan unsur-unsur timbunan kita, yang merupakan susunan generik jenis E :

private E[] elements;

Kedua, mari tambah konstruktor:

public MyStack(Class clazz, int capacity) { elements = (E[]) Array.newInstance(clazz, capacity); }

Perhatikan bagaimana kita menggunakan java.lang.reflect.Array # newInstance untuk memulakan array generik kami , yang memerlukan dua parameter. Parameter pertama menentukan jenis objek di dalam array baru. Parameter kedua menentukan berapa banyak ruang untuk dibuat untuk array. Hasil daripada Array # newInstance adalah Jenis objek , kita perlu membuangnya ke E [] untuk membuat susunan generik kita.

Kita juga harus memperhatikan konvensi penamaan parameter jenis clazz daripada kelas, yang merupakan kata cadangan di Java.

4. Mempertimbangkan ArrayList

4.1. Menggunakan ArrayList di Tempat Array

Selalunya lebih mudah menggunakan ArrayList generik sebagai ganti array generik. Mari lihat bagaimana kita dapat mengubah MyStack menggunakan ArrayList .

Pertama, mari buat medan untuk menyimpan elemen kami:

private List elements;

Kedua, dalam konstruktor timbunan kami, kami dapat menginisialisasi ArrayList dengan kapasiti awal:

elements = new ArrayList(capacity);

Ini menjadikan kelas kita lebih sederhana, kerana kita tidak perlu menggunakan refleksi. Juga, kami tidak diminta untuk masuk kelas literal semasa membuat timbunan kami. Akhirnya, kerana kita dapat menetapkan kapasiti awal ArrayList , kita dapat memperoleh faedah yang sama dengan array.

Oleh itu, kita hanya perlu membina susunan generik dalam situasi yang jarang berlaku atau ketika kita berinteraksi dengan beberapa perpustakaan luaran yang memerlukan array.

4.2. Pelaksanaan ArrayList

Menariknya, ArrayList sendiri dilaksanakan menggunakan tatasusunan generik. Mari kita lihat di dalam ArrayList untuk melihat caranya.

Pertama, mari lihat medan elemen senarai:

transient Object[] elementData;

Perhatikan ArrayList menggunakan Objek sebagai jenis elemen. Oleh kerana jenis generik kami tidak diketahui sehingga waktu operasi, Objek digunakan sebagai superclass dari jenis apa pun.

Perlu diingat bahawa hampir semua operasi di ArrayList dapat menggunakan array generik ini kerana mereka tidak perlu memberikan susunan yang sangat ditaip ke dunia luar, kecuali satu kaedah - toArray !

5. Membina Array dari Koleksi

5.1. Contoh Sambungan

Mari kita lihat menggunakan susunan generik di Java Collections API, di mana kita akan membina susunan baru dari koleksi.

Pertama, mari buat LinkedList baru dengan String argumen jenis dan tambahkan item ke dalamnya:

List items = new LinkedList(); items.add("first item"); items.add("second item"); 

Kedua, mari kita bina pelbagai item yang baru sahaja kita tambahkan:

String[] itemsAsArray = items.toArray(new String[0]);

Untuk membina susunan kami, Senarai . Kaedah toArray memerlukan array input. Ia menggunakan susunan ini semata-mata untuk mendapatkan maklumat jenis untuk membuat susunan pulangan dari jenis yang betul.

Dalam contoh di atas, kami telah menggunakan String baru [0] sebagai array input kami untuk membina array String yang dihasilkan .

5.2. Pelaksanaan LinkedList.toArray

Mari kita lihat di dalam LinkedList.toArray , untuk melihat bagaimana ia dilaksanakan di Java JDK.

Pertama, mari kita lihat tandatangan kaedah:

public  T[] toArray(T[] a)

Kedua, mari kita lihat bagaimana array baru dibuat apabila diperlukan:

a = (T[])java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), size);

Perhatikan bagaimana ia menggunakan Array # newInstance untuk membina array baru, seperti dalam contoh tumpukan kami sebelumnya. Juga, perhatikan bagaimana parameter a digunakan untuk memberikan jenis pada Array # newInstance. Akhirnya, hasil dari Array # newInstance dilancarkan ke T [] buat susunan generik.

6. Kesimpulannya

Dalam artikel ini, kami pertama kali melihat perbezaan antara tatasusunan dan generik, diikuti dengan contoh membuat susunan generik. Kemudian, kami menunjukkan bagaimana menggunakan ArrayList mungkin lebih mudah daripada menggunakan array generik. Akhirnya, kami juga melihat penggunaan array generik dalam API Koleksi.

Seperti biasa, kod contoh boleh didapati di GitHub.