本來這部分的內容是相對簡單的,但是在看書的過程中發現了一個很好的例子,涉及了好幾個知識點,忍不住要寫一篇博文。
泛型接口,顧名思義,泛型也可以應用於接口,接口使用泛型和類使用泛型沒什么區別。下面舉一個生成器的例子,是工廠方法的一種應用,負責創建對象的類。
生成器接口:
//接口方法返回類型是參數化的T,切記要與泛型方法進行區別;泛型方法是為了參數的泛化,后面我們將會給出一個簡單的實例
public interface Generator<T>{ T next();}
實體類結構:
public class Coffee {
private static long counter = 0;
private final long id = counter++;
public String toString() {
return getClass().getSimpleName() + " " + id;
}
}
class Latte extends Coffee {}
class Mocha extends Coffee {}
class Cappuccino extends Coffee {}
class Breve extends Coffee {}
class Americano extends Coffee {}
接口實現,目的是隨機生成對象
public class CoffeeGenerator implements Generator<Coffee>, Iterable<Coffee> {
private Class[] types = {Latte.class, Mocha.class, Cappuccino.class, Americano.class, Breve.class};
private static Random rand = new Random(47);
public CoffeeGenerator() {}
private int size = 0;
//構建末端哨兵
public CoffeeGenerator(int sz) { size = sz; }
//利用反射機制,隨機返回對象實例
public Coffee next() {
try {
return (Coffee)types[rand.nextInt(types.length)].newInstance();
} catch(Exception e) {
throw new RuntimeException(e);
}
}
//迭代器類的具體實現
class CoffeeIterator implements Iterator<Coffee> {
int count = size;
public boolean hasNext() { return count > 0; }
public Coffee next() {
count--;
return CoffeeGenerator.this.next();
}
public void remove() { // Not implemented
throw new UnsupportedOperationException();
}
};
//返回一個迭代器對象
public Iterator<Coffee> iterator() {
return new CoffeeIterator();
}
public static void main(String[] args) {
CoffeeGenerator gen = new CoffeeGenerator();
for(int i = 0; i < 5; i++){
System.out.println(gen.next());
}
for(Coffee c : new CoffeeGenerator(5)){
System.out.println(c);
}
}
}
當然,在這里不能給出確定的輸出,因為輸出結果是隨機產生的。
進一步地,我們可以嘗試用匿名內部類來改進iterator()方法:
public Iterator<Coffee> iterator() {
return new Iterator<Coffee> {
int count = size;
public boolean hasNext() { return count > 0; }
public Coffee next() {
count--;
return CoffeeGenerator.this.next();
}
public void remove() { // Not implemented
throw new UnsupportedOperationException();
}
};
}
該例子涉及的知識點:
泛型接口:正如前面說所,接口的泛型和類的泛型使用是沒有什么區別的。但需要注意的是,同時也是Java泛型的一個局限:基本類型無法作為類型參數。如果你需要使用它時,必須使用基本類型對應的包裝器類,包裝器類會自動進行打包拆包,所以我們正常使用即可。
迭代器:這里想重點強調的是Iterable
與Iterator
的用法,如果我們剛開始接觸,很容易混淆這兩個接口的的區別和用途。在這個例子中我們可以很好的理解他們的用途,Iterable
接口需要實現iterator()
方法,而iterator()
方法返回的是一個Iterator
類型的迭代器對象,所以真正實現迭代功能的是CoffeeIterator
。類實現了Iterable
接口,使得它可以在foreach
循環語句中使用。
反射機制:(Coffee)types[rand.nextInt(types.length)].newInstance()
在運行時確定創建的實例類型,在一定程度上這里就是一個生產Coffee
的工廠。
匿名內部類
為了區別返回類型為泛型的方法和泛型方法,舉一個簡單的對比實例:
返回類型為泛型的方法:
public interface Generator<T>{
T next();
}
泛型方法:
public interface Generator{
public <T> void f(T x);
}
泛型方法主要是為了在方法參數中使用泛型,是否擁有泛型方法,與其所在的類是否是泛型沒有關系。泛型方法使得該方法能夠獨立於類而產生變化。
使用泛型方法的原則:
public class Generator<T>{
//當然如果是接口的方法,那每個方法都是public static
public static <T> void f(T x);
}
到這里這個實例就基本講完了,一下子寫了這么些知識點,得好好消化消化了。
參考:
本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。