1.概述
我們之前討論過Java Generics
的基礎知識。在本文中,我們將瞭解Java中的通用建構函式。 泛型建構函式是至少需要有一個泛型型別引數的建構函式。我們將看到泛型建構函式並不都是在泛型類中出現的,而且並非所有泛型類中的建構函式都必須是泛型。
2.非泛型類
首先,先寫一個簡單的類:Entry,它不是泛型類:
public class Entry {
private String data;
private int rank;
}
複製程式碼
在這個類中,我們將新增兩個建構函式:一個帶有兩個引數的基本建構函式和一個通用建構函式。
2.1 基本構造器
Entry
第一個建構函式:帶有兩個引數的簡單建構函式:
public Entry(String data, int rank) {
this.data = data;
this.rank = rank;
}
複製程式碼
現在,讓我們使用這個基本建構函式來建立一個Entry
物件
@Test
public void givenNonGenericConstructor_whenCreateNonGenericEntry_thenOK() {
Entry entry = new Entry("sample", 1);
assertEquals("sample", entry.getData());
assertEquals(1, entry.getRank());
}
複製程式碼
2.2 泛型構造器
接下來,第二個構造器是泛型構造器:
public <E extends Rankable & Serializable> Entry(E element) {
this.data = element.toString();
this.rank = element.getRank();
}
複製程式碼
雖然Entry
類不是通用的,但它有一個引數為E
的泛型建構函式。
泛型型別E
是受限制的,應該實現Rankable
和Serializable
介面。
現在,讓我們看看Rankable
介面,下面是其中一個方法:
public interface Rankable {
public int getRank();
}
複製程式碼
假設我們有一個實現Rankable
介面的類——Product
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;
}
}
複製程式碼
然後我們可以使用泛型建構函式和Product
建立Entry
物件:
@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.泛型類
接下來,我們看一下泛型類:GenericEntry
public class GenericEntry<T> {
private T data;
private int rank;
}
複製程式碼
我們將在此類中新增與上一節相同的兩種型別的建構函式。
3.1 基礎構造器
首先,讓我們為GenericEntry
類編寫一個簡單的非泛型建構函式:
public GenericEntry(int rank) {
this.rank = rank;
}
複製程式碼
儘管GenericEntry
是泛型類,但這是一個簡單的,沒有任何引數的建構函式。
現在,我們可以使用此建構函式來建立GenericEntry
:
@Test
public void givenNonGenericConstructor_whenCreateGenericEntry_thenOK() {
GenericEntry<String> entry = new GenericEntry<String>(1);
assertNull(entry.getData());
assertEquals(1, entry.getRank());
}
複製程式碼
3.2 泛型構造器
接下來,在類中新增第二個建構函式:
public GenericEntry(T data, int rank) {
this.data = data;
this.rank = rank;
}
複製程式碼
這是一個泛型建構函式,它有一個泛型型別T的資料引數。注意,我們不需要在建構函式宣告中新增,因為它是隱含的。
現在,讓我們測試一下通用建構函式:
@Test
public void givenGenericConstructor_whenCreateGenericEntry_thenOK() {
GenericEntry<String> entry = new GenericEntry<String>("sample", 1);
assertEquals("sample", entry.getData());
assertEquals(1, entry.getRank());
}
複製程式碼
4.不同型別的泛型建構函式
在泛型類中,還有一個建構函式,其泛型型別與類的泛型型別不同:
public <E extends Rankable & Serializable> GenericEntry(E element) {
this.data = (T) element;
this.rank = element.getRank();
}
複製程式碼
GenericEntry
建構函式有型別為E
的引數,該引數與T
型別不同。讓我們看看它的實際效果:
@Test
public void givenGenericConstructorWithDifferentType_whenCreateGenericEntry_thenOK() {
Product product = new Product("milk", 2.5);
product.setSales(30);
GenericEntry<Serializable> entry = new GenericEntry<Serializable>(product);
assertEquals(product, entry.getData());
assertEquals(30, entry.getRank());
}
複製程式碼
注意:在示例中,我們使用Product(E)
建立Serializable(T)
型別的GenericEntry
,只有當型別E
的引數可以轉換為T
時,我們才能使用此建構函式。
5.多種泛型別
接下來,我們有兩個泛型型別引數的泛型類MapEntry
:
public class MapEntry<K, V> {
private K key;
private V value;
public MapEntry(K key, V value) {
this.key = key;
this.value = value;
}
}
複製程式碼
MapEntry
有一個兩個引數的泛型建構函式,每個引數都是不同的型別。讓我們用一個簡單的單元測試測試一下:
@Test
public void givenGenericConstructor_whenCreateGenericEntryWithTwoTypes_thenOK() {
MapEntry<String,Integer> entry = new MapEntry<String,Integer>("sample", 1);
assertEquals("sample", entry.getKey());
assertEquals(1, entry.getValue().intValue());
}
複製程式碼
6.萬用字元
最後,我們可以在泛型建構函式中使用萬用字元:
public GenericEntry(Optional<? extends Rankable> optional) {
if (optional.isPresent()) {
this.data = (T) optional.get();
this.rank = optional.get().getRank();
}
}
複製程式碼
在這兒,我們在GenericEntry
建構函式中使用萬用字元來繫結Optional
型別:
@Test
public void givenGenericConstructorWithWildCard_whenCreateGenericEntry_thenOK() {
Product product = new Product("milk", 2.5);
product.setSales(30);
Optional<Product> optional = Optional.of(product);
GenericEntry<Serializable> entry = new GenericEntry<Serializable>(optional);
assertEquals(product, entry.getData());
assertEquals(30, entry.getRank());
}
複製程式碼
請注意,我們應該能夠將可選引數型別(Product示例)轉換為GenericEntry
型別(Serializable示例)。
7.結束語
在本文中,我們學習瞭如何在泛型和非泛型類中定義和使用泛型建構函式。
完整的原始碼可以在GitHub
獲取(點選檢視原文)。
作者:baeldung
譯者:Emma
推薦關注公眾號:鍋外的大佬
每日推送國外優秀的技術翻譯文章,勵志幫助國內的開發者更好地成長!