Java泛型接口、迭代器與反射機制結合實例,和泛型方法的使用原則


本來這部分的內容是相對簡單的,但是在看書的過程中發現了一個很好的例子,涉及了好幾個知識點,忍不住要寫一篇博文。

泛型接口,顧名思義,泛型也可以應用於接口,接口使用泛型和類使用泛型沒什么區別。下面舉一個生成器的例子,是工廠方法的一種應用,負責創建對象的類。

生成器接口:

//接口方法返回類型是參數化的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泛型的一個局限:基本類型無法作為類型參數。如果你需要使用它時,必須使用基本類型對應的包裝器類,包裝器類會自動進行打包拆包,所以我們正常使用即可。

  • 迭代器:這里想重點強調的是IterableIterator的用法,如果我們剛開始接觸,很容易混淆這兩個接口的的區別和用途。在這個例子中我們可以很好的理解他們的用途,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);
}

泛型方法主要是為了在方法參數中使用泛型,是否擁有泛型方法,與其所在的類是否是泛型沒有關系。泛型方法使得該方法能夠獨立於類而產生變化。

使用泛型方法的原則:

  • 如果通過泛型方法能夠實現的事情,就盡量使用泛型方法而避免使用整個類型的泛化。
  • 對於一個static的方法,無法訪問泛型類型的類型參數。如果static方法需要使用泛型能力,就必須使其成為泛型方法。
public class Generator<T>{
//當然如果是接口的方法,那每個方法都是public static
public static <T> void f(T x);
}
  • 當使用泛型類型時,必須在創建對象的時候指定類型參數的值;而使用泛型方法時候,通常不必指明參數類型。

到這里這個實例就基本講完了,一下子寫了這么些知識點,得好好消化消化了。

參考:

  • 《Thinking in Java》

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
  © 2014-2022 ITdaan.com 联系我们: