Pembina Generik di Jawa

1. Gambaran keseluruhan

Kami sebelum ini membincangkan asas-asas Java Generics. Dalam tutorial ini, kita akan melihat Generic Constructors di Java.

Pembina generik adalah pembina yang mempunyai sekurang-kurangnya satu parameter jenis generik.

Kita akan melihat bahawa pembina generik tidak semestinya berada dalam kelas generik, dan tidak semua pembina dalam kelas generik harus generik.

2. Kelas Bukan Generik

Pertama, kami mempunyai Entry kelas sederhana , yang bukan kelas generik:

public class Entry { private String data; private int rank; }

Dalam kelas ini, kami akan menambah dua konstruktor: pembina asas dengan dua parameter, dan konstruktor generik.

2.1. Pembina Asas

Pembina Entri pertama adalah pembina sederhana dengan dua parameter:

public Entry(String data, int rank) { this.data = data; this.rank = rank; }

Sekarang, mari gunakan konstruktor asas ini untuk membuat objek Entri :

@Test public void givenNonGenericConstructor_whenCreateNonGenericEntry_thenOK() { Entry entry = new Entry("sample", 1); assertEquals("sample", entry.getData()); assertEquals(1, entry.getRank()); }

2.2. Pembina Generik

Seterusnya, konstruktor kedua kami adalah pembina generik:

public  Entry(E element) { this.data = element.toString(); this.rank = element.getRank(); }

Walaupun Kemasukan kelas bukan generik, ia mempunyai pembina generik, kerana ia mempunyai parameter elemen jenis E .

Jenis E generik dibatasi dan harus melaksanakan antara muka Rankable dan Serializable .

Sekarang, mari kita lihat antara muka Rankable , yang mempunyai satu kaedah:

public interface Rankable { public int getRank(); }

Dan, anggaplah kita mempunyai Produk kelas yang menerapkan antara muka Rankable :

public class Product implements Rankable, Serializable { private String name; private double price; private int sales; public Product(String name, double price) { this.name = name; this.price = price; } @Override public int getRank() { return sales; } }

Kita kemudian boleh menggunakan konstruktor generik untuk membuat objek Masuk menggunakan Produk :

@Test public void givenGenericConstructor_whenCreateNonGenericEntry_thenOK() { Product product = new Product("milk", 2.5); product.setSales(30); Entry entry = new Entry(product); assertEquals(product.toString(), entry.getData()); assertEquals(30, entry.getRank()); }

3. Kelas Generik

Seterusnya, kita akan melihat kelas generik yang dipanggil GenericEntry :

public class GenericEntry { private T data; private int rank; }

Kami akan menambah dua jenis konstruktor yang sama seperti bahagian sebelumnya dalam kelas ini juga.

3.1. Pembina Asas

Pertama, mari tulis konstruktor bukan generik yang ringkas untuk kelas GenericEntry kami :

public GenericEntry(int rank) { this.rank = rank; }

Walaupun GenericEntry adalah kelas generik, ini adalah konstruktor sederhana yang tidak mempunyai parameter jenis generik.

Sekarang, kita boleh menggunakan konstruktor ini untuk membuat GenericEntry :

@Test public void givenNonGenericConstructor_whenCreateGenericEntry_thenOK() { GenericEntry entry = new GenericEntry(1); assertNull(entry.getData()); assertEquals(1, entry.getRank()); }

3.2. Pembina Generik

Seterusnya, mari tambahkan konstruktor kedua ke kelas kami:

public GenericEntry(T data, int rank) { this.data = data; this.rank = rank; }

Ini adalah pembina generik, kerana ia mempunyai data parameter jenis generik T . Perhatikan bahawa kami tidak perlu menambah dalam pernyataan konstruktor, seperti yang tersirat di sana.

Sekarang, mari kita uji pembina generik kami:

@Test public void givenGenericConstructor_whenCreateGenericEntry_thenOK() { GenericEntry entry = new GenericEntry("sample", 1); assertEquals("sample", entry.getData()); assertEquals(1, entry.getRank()); }

4. Pembina Generik dengan Jenis Yang Berbeza

Di kelas generik kami, kami juga boleh mempunyai konstruktor dengan jenis generik yang berbeza dengan jenis generik kelas:

public  GenericEntry(E element) { this.data = (T) element; this.rank = element.getRank(); }

Ini GenericEntry pembina mempunyai parameter elemen dengan jenis E , yang berbeza dari T jenis. Mari kita lihat dalam tindakan:

@Test public void givenGenericConstructorWithDifferentType_whenCreateGenericEntry_thenOK() { Product product = new Product("milk", 2.5); product.setSales(30); GenericEntry entry = new GenericEntry(product); assertEquals(product, entry.getData()); assertEquals(30, entry.getRank()); }

Perhatikan bahawa:

  • Dalam contoh kami, kami menggunakan Produk ( E ) untuk membuat GenericEntry jenis Serializable ( T )
  • Kita hanya boleh menggunakan konstruktor ini apabila parameter jenis E dapat dilemparkan ke T

5. Jenis Generik Pelbagai

Seterusnya, kami mempunyai MapEntry kelas generik dengan dua jenis generik:

public class MapEntry { private K key; private V value; public MapEntry(K key, V value) { this.key = key; this.value = value; } }

MapEntry mempunyai satu konstruktor generik dengan dua parameter, masing-masing dari jenis yang berbeza. Mari gunakannya dalam ujian unit mudah:

@Test public void givenGenericConstructor_whenCreateGenericEntryWithTwoTypes_thenOK() { MapEntry entry = new MapEntry("sample", 1); assertEquals("sample", entry.getKey()); assertEquals(1, entry.getValue().intValue()); }

6. Kad liar

Akhirnya, kita boleh menggunakan wildcard dalam pembina generik:

public GenericEntry(Optional optional) { if (optional.isPresent()) { this.data = (T) optional.get(); this.rank = optional.get().getRank(); } }

Di sini, kami menggunakan wildcard dalam konstruktor GenericEntry ini untuk mengikat jenis Pilihan :

@Test public void givenGenericConstructorWithWildCard_whenCreateGenericEntry_thenOK() { Product product = new Product("milk", 2.5); product.setSales(30); Optional optional = Optional.of(product); GenericEntry entry = new GenericEntry(optional); assertEquals(product, entry.getData()); assertEquals(30, entry.getRank()); }

Perhatikan bahawa kita seharusnya dapat memasukkan jenis parameter pilihan (dalam kes kita, Produk ) ke jenis GenericEntry (dalam kes kita, Serializable ).

7. Kesimpulannya

Dalam artikel ini, kami belajar bagaimana menentukan dan menggunakan konstruktor generik di kedua-dua kelas generik dan bukan generik.

Kod sumber lengkap boleh didapati di GitHub.