第十五章 泛型
15.1 与C++的比较
15.2 简单泛型
泛型类
package com.mzm.chapter15;
/**
*
* 泛型类,持有泛化类型的对象,取出对象无需转型
*/
public class Holder3<T> {
private T a;
public Holder3(T a){
this.a = a;
}
public void set(T a) {
this.a = a;
}
public T get(){
return a;
}
public static void main(String[] args){
Holder3<Automobile> h3 = new Holder3<>(new Automobile());
Automobile a = h3.get();
}
}
15.2.1 一个元组类库
元组(tuple)是将一组对象直接打包存储的容器对象,这一容器对象容许读取其中的元素,但是不允许存放新的对象。元组也被称为数据传送对象或信使。
元组具有任意长度,其持有的对象可以是不同类型的。
package com.mzm.chapter15;
/**
* 二维元组
*
*/
public class TwoTuple<A, B> {
public final A first;
public final B second;
public TwoTuple(A a, B b){
this.first = a;
this.second = b;
}
public String toString(){
return "(" + first + ", " + second + ")";
}
}
package com.mzm.chapter15;
/**
* 三维元组,使用继承机制实现长度更长的元组
*
*/
public class ThreeTuple<A, B, C> extends TwoTuple<A, B> {
public final C third;
public ThreeTuple(A a, B b, C c) {
super(a, b);
this.third = c;
}
public String toString() {
return "(" + first + ", " + second + ", " + third + ")";
}
}
更长的元组依次类推。
15.2.2 一个堆栈类
传统的下推堆栈
package com.mzm.chapter15;
/**
*
*/
public class LinkedStack<T> {
private static class Node<U> {
U item;
Node<U> next;
Node() {
this.item = null;
this.next = null;
}
Node(U item, Node<U> next) {
this.item = item;
this.next = next;
}
/**
* 末端哨兵,判断堆栈是否为空
* @return
*/
boolean end() {
return item == null && next == null;
}
}
private Node<T> top = new Node<>();
public void push(T item) {
top = new Node<>(item, top);
}
public T pop() {
T result = top.item;
if (!top.end()) {
top = top.next;
}
return result;
}
public static void main(String[] args) {
LinkedStack<String> lss = new LinkedStack<>();
for (String s : "Phasers on stun!".split(" ")) {
lss.push(s);
}
String s;
while((s = lss.pop()) != null) {
System.out.println(s);
}
}
}
15.2.3 RandomList
package com.mzm.chapter15;
import java.util.ArrayList;
import java.util.Random;
/**
*
*/
public class RandomList<T> {
private ArrayList<T> storage = new ArrayList<>();
private Random rand = new Random(47);
public void add(T item) {
storage.add(item);
}
public T select() {
return storage.get(rand.nextInt(storage.size()));
}
public static void main(String[] args) {
RandomList<String> rs = new RandomList<>();
for(String s : "The quick brown fox jumped over the lazy brown dog".split(" ")) {
rs.add(s);
}
for(int i = 0; i < 11; i++) {
System.out.print(rs.select() + " ");
}
}
}
15.3 泛型接口
泛型接口的例子:
生成器(generator),是一种专门负责创建对象的类,是工厂方法设计模式的一种应用。不同的是,使用生成器创建对象时,不需要任何参数,而工厂方法一般需要参数。
package com.mzm.chapter15;
/**
* 生成器的通用接口
*/
public interface Generator<T> {
T next();
}
package com.mzm.chapter15;
import java.util.Iterator;
import java.util.Random;
/**
* 使用生成器接口生成对象
*/
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) {
this.size = sz;
}
@Override
public Coffee next() {
try {
return (Coffee) types[rand.nextInt(types.length)].newInstance();
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
class CoffeeIterator implements Iterator<Coffee> {
int count = size;
@Override
public boolean hasNext() {
return count > 0;
}
@Override
public Coffee next() {
count--;
return CoffeeGenerator.this.next();
}
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());
}
for(Coffee c : new CoffeeGenerator(5)) {
System.out.println(c);
}
}
}
15.4 泛型方法
是否拥有泛型方法与该类是不是泛型类无关。
定义泛型方法只需要将泛型参数列表置于返回值之前。
使用泛型类创建对象时必须指定类型参数,而在使用泛型方法时则不必指定类型参数,编译器会进行类型参数推断(type argument inference),找出具体的类型。
15.4.1 杠杆利用类型参数推断
类型推断只对赋值操作有效,不能将一个泛型方法的返回结果作为参数,传递给另一个方法,因为编译器认为,泛型方法的返回值是被赋值给一个Object类型的变量(泛型方法的返回值类型实际上是Object类型?)。
显式类型说明
要想实现上述目的,可以使用显式类型说明。即在点操作符与方法名之间插入尖号,并指明类型。如果是在定义该方法的类内部,则在点操作符之前使用this关键字,如果是static方法,则在点操作符之前加类名。
package com.mzm.chapter15;
import com.mzm.chapter14.Person;
import com.mzm.chapter14.Pet;
import java.util.List;
import java.util.Map;
/**
*
*/
public class LimitsOfInference {
static void f(Map<Person, List<Pet>> petPeople) {
}
public static void main(String[] args) {
//f(New.map();
f(New.<Person, List<Pet>>map());
}
}
15.4.2 可变参数与泛型方法
可变参数可与泛型方法并存
15.4.3 用于Generator的泛型方法
15.4.4 一个通用的Generator
package com.mzm.chapter15;
/**
*
*/
public class BasicGenerator<T> implements Generator<T> {
private Class<T> type;
public BasicGenerator(Class<T> type) {
this.type = type;
}
@Override
public T next() {
try {
return type.newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static <T> Generator<T> create(Class<T> type) {
return new BasicGenerator<>(type);
}
}
15.4.5 简化元组的使用
15.4.6 一个Set实用工具
package com.mzm.chapter15;
import java.util.HashSet;
import java.util.Set;
/**
* 集合的各种运算
*
*/
public class Sets {
public static <T> Set<T> union(Set<T> a, Set<T> b) {
Set<T> result = new HashSet<>(a);
result.addAll(b);
return result;
}
public static <T> Set<T> intersection(Set<T> a, Set<T> b) {
Set<T> result = new HashSet<>(a);
result.retainAll(b);
return result;
}
public static <T> Set<T> difference(Set<T> superset, Set<T> subset) {
Set<T> result = new HashSet<>(superset);
result.removeAll(subset);
return result;
}
public static <T> Set<T> complement(Set<T> a, Set<T> b) {
return difference(union(a, b), difference(a, b));
}
}
15.5 匿名内部类
将泛型应用于匿名内部类
package com.mzm.chapter15;
import java.util.*;
/**
* Teller和Customer的默认构造器均为private,必须使用Generator创建对象
*
*/
public class BankTeller {
public static void serve(Teller t, Customer c) {
System.out.println(t + " servers " + c);
}
public static void main(String[] args) {
Random rand = new Random(47);
Queue<Customer> line = new LinkedList<>();
Generators.fill(line, Customer.generator(), 15);
List<Teller> tellers = new ArrayList<>();
Generators.fill(tellers, Teller.generator(), 4);
for(Customer c : line) {
serve(tellers.get(rand.nextInt(tellers.size())), c);
}
}
}
class Customer {
private static long counter = 1;
private final long id = counter++;
private Customer() {
}
public String toString() {
return getClass().getSimpleName() + " " + id;
}
public static Generator<Customer> generator() {
return new Generator<Customer>() {
@Override
public Customer next() {
return new Customer();
}
};
}
}
class Teller {
private static long counter = 1;
private final long id = counter++;
private Teller() {
}
public String toString() {
return getClass().getSimpleName() + " " + id;
}
public static Generator<Teller> generator() {
return new Generator<Teller>() {
@Override
public Teller next() {
return new Teller();
}
};
}
}
15.6 构建复杂模型
泛型可以简单而安全地创建复杂的模型。