泛型接口的概念
泛型也可以運(yùn)用于接口,例如生成器(generator),這是一種專門負(fù)責(zé)創(chuàng)建對(duì)象的類,實(shí)際上,這是工廠方法設(shè)計(jì)模式的一種應(yīng)用。不過兩者之間不同的是,生成器的調(diào)用不需要任何參數(shù),但是工廠方法一般需要參數(shù)來調(diào)用。這就意味著生成器不需要額外的信息去生成新的對(duì)象。
生成器接口的定義
一般來說,一個(gè)生成器只定義一個(gè)方法,該方法用于產(chǎn)生新的對(duì)象。在這里,就是next()方法。
public interface Generator<T> {
T next();
}
創(chuàng)建Coffee生成器
首先我們需要一些類以供生成
// Coffee.java
public class Coffee {
private static long counter = 0;
private final long id = counter++;
@Override
public String toString() {
return getClass().getSimpleName() + " " + id;
}
}
// Latte.java
public class Latte extends Coffee{}
// Mocha.java
public class Mocha extends Coffee{}
// Cappuccino.java
public class Cappuccino extends Coffee{}
// Americano.java
public class Americano extends Coffee{}
// Breve.java
public class Breve extends Coffee{}
接著我們創(chuàng)建一個(gè)生成器
public class CoffeeGenerator implements Generator<Coffee>, Iterable<Coffee> {
private Class[] types = {Latte.class, Mocha.class, Cappuccino.class, Americano.class, Breve.class};
private Random rand = new Random(47);
public CoffeeGenerator() {
}
private int size = 0;
public CoffeeGenerator(int size) {
this.size = size;
}
@Override
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;
}
@Override
public Coffee next() {
count--;
return CoffeeGenerator.this.next();
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
@Override
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() = " + gen.next());
}
for (Coffee coffee : new CoffeeGenerator(5)) {
System.out.println("coffee = " + coffee);
}
}
}
// Outputs
gen.next() = Americano 0
gen.next() = Latte 1
gen.next() = Americano 2
gen.next() = Mocha 3
gen.next() = Mocha 4
coffee = Americano 5
coffee = Latte 6
coffee = Americano 7
coffee = Mocha 8
coffee = Mocha 9
參數(shù)化的Generatoer的接口確保next()的返回值是參數(shù)的類型。CoffeeGenerator同時(shí)還實(shí)現(xiàn)了Iterable接口,所以它可以在ForEach循環(huán)中被使用。不過,它還需要一個(gè)“末端哨兵”來判斷何時(shí)停止,這正是第二個(gè)構(gòu)造器的功能。
創(chuàng)建Fibonacci數(shù)列生成器
下面的類也實(shí)現(xiàn)了Generator<T>接口,它負(fù)責(zé)生成Fibonacci數(shù)列
public class Fibonacci implements Generator<Integer> {
private int count = 0;
public Integer next() {
return fib(count++);
}
private int fib(int n) {
if (n < 2) {
return 1;
}
return fib(n - 2) + fib(n - 1);
}
public static void main(String[] args) {
Fibonacci gen = new Fibonacci();
for (int i = 0; i < 18; i++) {
System.out.print(gen.next() + " ");
}
}
}
// Outputs
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584
這里注意到,雖然在Fibonacci里面使用的都是int類型,但是其參數(shù)類型確是Integer。這是因?yàn)镴ava泛型的局限性:基本類型無法作為類型參數(shù)。但是Java SE5提供了自動(dòng)包裝和拆包的功能,可以很方便地在基本類型和其相應(yīng)的包裝器類型之間進(jìn)行轉(zhuǎn)換。
編寫實(shí)現(xiàn)了Iterable的Fibonacci生成器
如果還想更進(jìn)一步,編寫一個(gè)實(shí)現(xiàn)了Iterable的Fibonacci生成器。一個(gè)選擇是重寫這個(gè)類,令其實(shí)現(xiàn)Iterable接口。
但是我們并不能總是擁有源代碼的控制權(quán),并且,除非必須這么做,否則我們也不愿意重寫一個(gè)類。而且我們還有另一種選擇,就是創(chuàng)建一個(gè)適配器(adapter)來是實(shí)現(xiàn)所需的接口。
public class IterableFibonacci extends Fibonacci implements Iterable<Integer> {
private int n;
public IterableFibonacci(int count) {
this.n = count;
}
@Override
public Iterator<Integer> iterator() {
return new Iterator<Integer>() {
@Override
public boolean hasNext() {
return n > 0;
}
@Override
public Integer next() {
n--;
return IterableFibonacci.this.next();
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
public static void main(String[] args) {
for (int i : new IterableFibonacci(18)) {
System.out.print(i + " ");
}
}
}
// Outputs
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584
這里通過使用了繼承來實(shí)現(xiàn)了適配器。