Yang disebut generik: Memungkinkan Anda menentukan parameter tipe saat mendefinisikan kelas dan antarmuka. Parameter tipe ini akan ditentukan saat mendeklarasikan variabel dan membuat objek (yaitu, meneruskan parameter tipe aktual, yang juga bisa disebut argumen tipe)
Kelas atau antarmuka generik
Kode salinan sintaksis "berlian" adalah sebagai berikut:
//definisi
antarmuka publik Daftar<E> memperluas Koleksi<E>
kelas publik HashMap<K,V> memperluas AbstrakMap<K,V> mengimplementasikan Peta<K,V>, Dapat Dikloning, Dapat Diserialkan
//menggunakan
Daftar<String> daftar = ArrayList baru();
//Setelah Java 7, Anda dapat menghilangkan parameter tipe kurung sudut di belakangnya.
Daftar<String> daftar = Daftar Array baru<>();
Turunkan subkelas dari kelas generik
Copy kode kodenya sebagai berikut:
//Metode 1
Aplikasi kelas publik memperluas GenericType<String>
//Metode 2
Aplikasi kelas publik<T> memperluas GenericType<T>
//Metode 3
Aplikasi kelas publik memperluas GenericType
Obat generik semu
Tidak ada kelas generik yang sebenarnya. Kelas generik transparan terhadap mesin virtual Java. JVM tidak mengetahui keberadaan kelas generik. Dengan kata lain, JVM memproses kelas generik tidak berbeda dengan kelas biasa dalam metode statis, blok inisialisasi statis, dan variabel statis.
- Cara-cara berikut ini semuanya salah. Salin kode kodenya sebagai berikut:
data T statis pribadi;
statis{
Tf;
}
fungsi kekosongan statis publik(){
T nama = 1;
}
Contoh berikut dapat memverifikasi dari samping bahwa tidak ada kelas generik. Salin kodenya sebagai berikut:
public static void main(String[] args){
Daftar<String> a1 = Daftar Array baru<>();
Daftar<Bilangan Bulat> a2 = Daftar Array baru<>();
Sistem.keluar.println(a1.getClass() == a2.getClass());
Sistem.keluar.println(a1.getClass());
Sistem.keluar.println(a2.getClass());
}
Kode salinan keluarannya adalah sebagai berikut:
BENAR
kelas java.util.ArrayList
kelas java.util.ArrayList
Ketik karakter pengganti
Pertama-tama, harus jelas bahwa jika Foo adalah kelas induk dari Bar, tetapi List<Foo> bukan kelas induk dari Daftar<Bar>. Untuk mewakili berbagai kelas induk generik, Java menggunakan "?" wildcard generik. Artinya, List<?> mewakili kelas induk dari berbagai Daftar generik. Dengan wildcard semacam ini, Daftar generik tidak dapat menyetel (mengatur) elemen, tetapi hanya dapat memperoleh (mendapatkan) elemen. Karena program tidak dapat menentukan tipe dalam Daftar, maka program tidak dapat menambahkan objek. Namun objek yang didapat harus bertipe Object.
Metode berikut akan dikompilasi dengan kesalahan:
Copy kode kodenya sebagai berikut:
Daftar<?> daftar = Daftar Array baru<>();
list.add(Objek baru());
Beberapa ide:
1. Objek Daftar<String> tidak dapat digunakan sebagai objek Daftar<Objek>, artinya: Kelas Daftar<String> bukan merupakan subkelas dari kelas Daftar<Objek>.
2. Array berbeda dari generik: dengan asumsi Foo adalah subtipe (subkelas atau subantarmuka) dari Bar, maka Foo[] masih merupakan subtipe dari Bar[]; tetapi G<Foo> bukan subtipe G<Bar>.
3. Untuk mewakili kelas induk dari berbagai Daftar generik, kita perlu menggunakan tipe wildcard. Tipe wildcard adalah tanda tanya (?). Berikan tanda tanya sebagai argumen tipe ke koleksi Daftar, yang ditulis: List<? > (artinya Daftar elemen tipe tidak diketahui). Tanda tanya (?) ini disebut karakter wildcard, dan tipe elemennya bisa cocok dengan tipe apa pun.
Batas atas karakter pengganti
List<? extends SuperType> mewakili kelas induk atau dirinya sendiri dari semua Daftar generik SuperType. Generik dengan batas atas wildcard tidak dapat menetapkan metode, hanya mendapatkan metode.
Menetapkan batas atas wildcard dapat menyelesaikan masalah berikut: Anjing merupakan subkelas Hewan, dan terdapat metode getSize untuk mendapatkan jumlah Daftar yang masuk. Salin kodenya sebagai berikut:
kelas abstrak Hewan {
abstrak publik void run();
}
kelas Anjing memperluas Hewan {
menjalankan kekosongan publik() {
System.out.println("Anjing lari");
}
}
Aplikasi kelas publik {
public static void getSize(Daftar<Hewan> daftar) {
Sistem.keluar.println(daftar.ukuran());
}
public static void main(String[] args) {
Daftar<Anjing> daftar = Daftar Array baru<>();
getSize(daftar); // Kesalahan kompilasi di sini
}
}
Alasan kesalahan pemrograman di sini adalah karena List<Animal> bukan kelas induk dari List<Dog>. Solusi pertama adalah mengubah parameter formal Daftar<Animal> dalam metode getSize menjadi Daftar<?>, tetapi dalam kasus ini, konversi tipe paksa diperlukan setiap kali objek diperoleh, yang lebih merepotkan. Menggunakan batas atas wildcard memecahkan masalah ini dengan sangat baik. Anda dapat mengubah List<Animal> menjadi List<? extends Animal>, dan tidak akan ada kesalahan dalam kompilasi, dan tidak diperlukan konversi jenis.
Batas bawah untuk wildcard
List<? super SubType> mewakili batas bawah Daftar generik SubType. Generik dengan batas atas wildcard tidak dapat memiliki metode get, hanya metode set.
Metode umum
Jika Anda mendefinisikan kelas dan antarmuka tanpa menggunakan parameter tipe, tetapi ingin menentukan sendiri parameter tipe saat mendefinisikan metode, JDK1.5 juga menyediakan dukungan untuk metode generik. Tanda tangan metode dari metode generik memiliki lebih banyak deklarasi parameter tipe daripada tanda tangan metode dari metode biasa. Deklarasi parameter tipe diapit dalam tanda kurung siku. Beberapa parameter tipe dipisahkan dengan koma (,). pengubah dan tipe nilai pengembalian metode. Format sintaksisnya adalah sebagai berikut:
Copy kode kodenya sebagai berikut:
Pengubah nama metode tipe nilai kembalian (daftar tipe) {
//tubuh metode
}
Metode generik memungkinkan parameter tipe digunakan untuk mengekspresikan ketergantungan tipe antara satu atau lebih parameter suatu metode, atau antara nilai dan parameter pengembalian metode. Jika tidak ada ketergantungan tipe seperti itu, metode generik tidak boleh digunakan. Metode penyalinan Koleksi menggunakan metode umum:
Copy kode kodenya sebagai berikut:
public static <T> void copy(Daftar<? super T> tujuan, Daftar<? extends T> src){ ...}
Metode ini mengharuskan tipe src harus merupakan subkelas dari tipe tujuan atau dirinya sendiri.
Hapus dan ubah
Dalam kode generik yang ketat, kelas dengan deklarasi generik harus selalu memiliki parameter tipe. Namun, agar konsisten dengan kode Java lama, diperbolehkan juga menggunakan kelas dengan deklarasi generik tanpa menentukan parameter tipe. Jika tidak ada parameter tipe yang ditentukan untuk kelas generik ini, parameter tipe disebut tipe mentah dan defaultnya adalah tipe batas atas pertama yang ditentukan saat parameter dideklarasikan.
Ketika sebuah objek dengan informasi umum ditugaskan ke variabel lain tanpa informasi umum, semua informasi tipe di antara tanda kurung sudut akan dibuang. Misalnya, jika tipe Daftar<String> dikonversi ke Daftar, pemeriksaan tipe elemen kumpulan Daftar menjadi batas atas variabel tipe (yaitu, Objek). Situasi ini disebut penghapusan.
Contoh kode salinannya adalah sebagai berikut:
kelas Apple<T memperluas Nomor>
{
ukuran T;
publikApple()
{
}
Apple publik (ukuran T)
{
this.ukuran = ukuran;
}
ukuran set kekosongan publik (ukuran T)
{
this.ukuran = ukuran;
}
getSize T publik()
{
kembalikan ini.ukuran;
}
}
ErasureTest kelas publik
{
public static void main(String[] args)
{
Apple<Bilangan Bulat> a = Apple baru<>(6); // ①
// Metode getSize dari a mengembalikan objek Integer
Integer sebagai = a.getSize();
// Tetapkan objek a ke variabel Apple, sehingga informasi tipenya hilang dalam tanda kurung siku
Apel b = a; // ②
// b hanya mengetahui bahwa tipe ukurannya adalah Angka
Angka size1 = b.getSize();
//Kode berikut menyebabkan kesalahan kompilasi
Ukuran bilangan bulat2 = b.getSize(); // ③
}
}