|     java thinking in java generics   |    

泛型的语法

泛型的基本动机:让代码适应不同的数据类型,更好地复用。比如说“容器”

Holder类是个最简单的容器。用来储存和操作内部单一元素。

public class Holder<T>{
	//字段
    private T t;
    //构造函数
    public Holder(T inT){t=inT;}
	//成员方法
    public void set(T inT){t=inT;}
    public String toString(){return t.toString();}
}

两种情况:

  1. 类型声明的时候,后面在尖括号<>里加上“类型参数”。
  2. 构造函数和方法声明名称的前后不用写类型参数。
    public static void main(String[] args){
        Pet p=new Pet();
        Dog d=new Dog();

        Holder<Pet> h=new Holder<Pet>(p);
        h.set(d);
    }

注意

  1. 数组不接受泛型
  2. 基本型无法作为类型参数
  3. 静态方法不能访问类型参数

泛型接口

和泛型类一样的用法。

public interface Generator<T>{public T next();}

泛型方法

语法只需要把泛型参数列表置于返回类型之前。下面例子里void后面的<T>就是参数类型列表。

public class Test{
	public static void <T> f(T t){
		//do something
	}
}

参数类型推断(Type Argument Inference)

上面例子里的泛型方法 f(),调用的时候,不需要像泛型类那样显式的标明参数类型。

Test.f("hello");
Test.f(1);
Test.f(1.0);

泛型内部类

当一个泛化类的内部还有一个泛化的内部类的时候,怎么处理? 看下面这个例子:

interface Interface<U>{ public U getLast();}

public class GenericsDemo<T>{
	//成员字段
    private List<T> content=new ArrayList<T>();
	//成员方法
    public void add(T t){content.add(t);}
    public T getFirst(){return (content.size()>0)? content.get(0) : null;}

	//!!!注意:这里不能写成Inner<T>。不然编译器会误解T代表另一个新的类型参数,而不是外部主类中的类型参数T。
    class Inner implements Interface<T>{
        public T getLast(){return (content.size()>0)? content.get(content.size()-1) : null;}
    }

	//获取内部类引用
    public Interface<T> getInterface(){return this.new Inner();}
}

实用主义的描述:

如果希望外部类的类型参数 “T” 在内部类里也保持相同的含义,在声明内部函数Inner的时候,就不要再设一个类型参数。

怎么调用上面的泛型内部类,看下面这个例子:

    public static void main(String[] args){
        GenericsDemo<String> gd=new GenericsDemo<String>();
        gd.add("Hello World");

        GenericsDemo<String>.Inner i1=gd.new Inner();
        Interface<String> i2=gd.new Inner();
        Interface<String> i3=gd.getInterface();
    }

书里LinkedStack的例子里的内部类Node,就是一个反例,**``** 代表的是内部类自己的类型参数。

public class LinkedStack<T> {

    private static class Node<U> {
        U item;
        Node<U> next;
        Node() { item = null; next = null; }
        Node(U item, Node<U> next) {
            this.item = item;
            this.next = next;
        }
        boolean end() { return item == null && next == null; }
    }

	//... ...
}

擦除(Erase)

Java的泛型是用 “擦除” 的方式实现的。所谓擦除,就是说在运行时JVM是看到的是没有类型参数的“原生类”。比如ArrayList容器,

List<String> ls=new ArrayList<String>();
System.out.println(ls.getClass());

//Output: class java.util.ArrayList

例子里的类型参数<String>只负责在编译期做类型检查,运行时JVM看到的是原生类“ArrayList”。

再看两个例子。第一,有一个存String和一个存Integer的ArrayList。比较他们的Class对象,类型相同。

Class c1 = new ArrayList<String>().getClass();
Class c2 = new ArrayList<Integer>().getClass();
System.out.println(c1 == c2);

// Output: true

第二个例子,我们尝试用Class#getTypeParameters()方法获得泛型的类型参数。

class A {}

public class Test {
	public static void main(String[] args) {
		List<A> list = new ArrayList<A>();
		System.out.println(Arrays.toString(list.getClass().getTypeParameters()));
	}
}
// Output:[E]

结果返回的并不是真正的类型参数A,而是定义ArrayList时候的占位符。

C++的模板:Reifiable generics

首先,和Java的擦除比,C++的模板是具体化(Reifiable)的:在编译期全展开,比如定义一个A类模板:

template<class T> class A{
    public:
        T g(T a,T b);
        A();
};

然后定义一个A类实例。

void main(){
    A<int> a;
}

对编译器来说很清楚,A<int>类就是A<int>。不是A<String>。所以C++的类型很精确。

因为擦除,Java泛型做不了什么?

对Java来说,像下面这样,调用泛型对象的fff()方法,编译器是通不过的。因为编译器在Runtime之前,无法知道泛型T的具体类型,是否有fff()方法。

class BBB {public fff(){}}

public class AAA<T> {
	T t;
	public AAA(T t){this.t=t;}

	public callF(){
		t.fff();
	}
}

为什么Java要用擦除实现泛型?

后面还会讲到,Java用擦除实现泛型,会导致非常多的麻烦。为什么Java不实现像C++这样具体化的泛型,而是要用擦除?

关于这个问题,先可以看知乎上的一个问题:《Java不能实现真正泛型的原因?》。尤其是RednexelaFX的回答。 还可以参考另一个回答:《Reifiable generics与Type erasure generics各有怎样的优点与缺点?》

简单讲,首先,Java不是技术上“实现不了”。在2014的Project Valhalla里,就已经实现过。用擦除是为了 “向后兼容” 的考虑。引用Martin Odersky的原话:

泛型不是在Java1.0就有的特性。而是在Java 5才加进来的。所以Java强调的向后兼容,是 “二进制向后兼容(binary backwards compatibility)”

也就是每一个在Java1,Java2等老版本上能正常运行的的class文件,放在Java5,6,7,8的JRE上也要正常运行。实际上在加入Java5加入泛型之前,java的类库已经经过好几年发展,有一定规模了。如果为了新泛型,把过去的类库全部推倒重来是不现实的。这就是所谓的“历史包袱”。

在这个背景下,要让老版本的没有泛型的ArrayList,在支持泛型的虚拟机上运行,擦除是最简单的办法。

泛型类型参数擦除到第一个边界

还是上面这个例子,如果声明AAA类的泛型参数T的时候,加上一个 “边界”:extends BBB。编译就能通过了。因为这时候编译器会**把从左往右擦除**,直到第一个边界“BBB”。所以,剩下的就是 **“public class AAA”**。这时候,编译器就能检查BBB类有没有实现fff()方法了。

class BBB {public fff(){}}

public class AAA<T extends BBB> {
	T t;
	public AAA(T t){this.t=t;}

	public callF(){
		t.fff();
	}
}

泛型数组

Java不允许泛型数组。因为数组是强类型的,在运行时必须检测到实际数据类型,创建数组的时候必须知道数组中元素的具体类型。 具体可以参考另一篇专题:《Java为什么不支持泛型数组?》

运行时类型检查的好处

因为数组在运行时做类型检查,所以基类数组里能存放派生类对象。这叫数组的“协变”。

Number[] numArray=new Integer[10];

一个Number数组,可以用所有Number类的派生类Integer,Long,Short,Float,Double等等的数组来为Number[]数组赋值。因为数组做运行时类型检查,不怕。

但不做运行时检查的Collection容器,比如List就不行。

List<Number> numList=new ArrayList<Integer>();

对编译器来讲,List不是List。因为泛型擦除之后都是List,容器运行时无法做类型检查,所以编译器不允许用List为List赋值。

两种方法声明泛型数组

接受检查的强类型方法(理论上更好的方法)
public class GenSet<E> {

    private E[] a;

    public GenSet(Class<E> c, int s) {
        // Use Array native method to create array
        // of a type only known at run time
        @SuppressWarnings("unchecked")
        final E[] a = (E[]) Array.newInstance(c, s);
        this.a = a;
    }

    E get(int i) {
        return a[i];
    }
}
不接受检查的弱类型方法(JDK里普遍使用)
public class GenSet<E> {

    private Object[] a;

    public GenSet(int s) {
        a = new Object[s];
    }

    E get(int i) {
        @SuppressWarnings("unchecked")
        final E e = (E) a[i];
        return e;
    }
}
第二种方法里需要注意

不能给对象数组Object[]转型。因为String[]和Object[]之间不存在IS-A的关系。

Object[] o=new Object[1];
String[] s=new String[1];
s[0]="hello";

s=(String)o;

所以,下面例子里的操作是不允许的。

public class Test<T>{
    private Object[] o;
    public Test3(int num){o=new Object[num];}

    public void add(T t, int index){
        if(index<o.length){
            o[index]=t;
        }
    }
	//单个元素转型:可以
    public T get(int index){return (index<o.length)? (T)o[index] : null;}
	//对数组转型:报错
    public T[] getAll(){return (T[])o;}	//Error
}

桥方法

另一个Java擦除引起的麻烦在反省类被继承的时候发生。Java核心技术里给出下面这个例子:(参见:Java核心技术卷1:P536) 假设我有个泛型类Pair。

class Pair<T>{
	private T first;
	private T second;

	public T getFirst(){return first;}
	public void setSecond(T t){seconde=t;}
}

然后有一个表示日期区间的派生类DateInteval。它为了确保日期区间的第二个值比第一个大,重写了基类Pair的setSecond()方法。

class DateInteval extends Pair<Date>{
	public void setSecond(Date d){
		if(d.compareTo(getFirst())>=0){
			second=d;
		}
	}
}

这时候就会产生一个问题,实际上DateInteval类同时具备两个setSecond方法,后面的重写的setSecond方法没有覆盖掉基类Pair的setSecond方法,因为参数类型不同。

public void setSecond(Object o);	//继承自基类Pair。
public void setSecond(Date d);

如果这时候我给setSecond方法传递一个Object对象,就会错误调用继承自基类的版本。这可能不是程序员想要的。

DateInteval di=new DateInteval();
Object o=new Object();
di.setSecond(o);

所以实际上JVM在这个时候会自动合成一个 “桥方法(Bridge Method)”

public void setSecond(Object o){setSecond((Date)o);}

这样,当我们像前面这样给setSecond传递一个Object对象的时候,会自动跳转调用正确的setSecond(Date)方法。然后因为参数类型不匹配,会抛出ClassCastException异常。

通配符

一篇IBM Developer上的文章 《Java 理论与实践: 使用通配符简化泛型使用》

贴两张图: extends super

具体可以参考另两篇专题:《Java泛型中extends和super的区别?》《通配符”?”和类型参数”T”的区别?》

PECS原则

PECS(Producer Extends Consumer Super)原则是要记住的:

具体细节还是参看上面两篇专题。

关于无界通配符的第一个例子

通过这个例子,理解一下通配符的捕获机制。

当一个通配符捕获一个运行时具体类型之后,会被标记成CAP#XXX。就不接受任何具体类型的操作。看下面这个例子感受一下。

class Ticket<T>{
    private T info;
    public Ticket(T t){info=t;}
    public void set(T t){info=t;}
    public String toString(){return info.toString();}
}

class Box<V>{
    private V item;
    public void set(V v){item=v;}
    public String toString(){return item.toString();}

}

public class TestWildcards{
    public static void main(String[] args){
        /**
         *  Box<Ticket<?>>里什么Ticket都能放。因为通配符没有捕获类型。
         */
        Box<Ticket<?>> box=new Box<Ticket<?>>();

        Ticket<Integer> ti=new Ticket<Integer>(111);
        Ticket<String> ts=new Ticket<String>("Hello");

        box.set(ti);
        System.out.println(box);
        box.set(ts);
        System.out.println(box);

        /**
         *  Ticket<?>被赋值一种泛型之后,就所有的操作都不能做了。因为通配符捕获运行时实际类型后,标记为CAP#1。
         */
        Ticket<?> t=new Ticket<String>("World");
        //t.set(111);   //ERROR, 什么类型都不接受
        //t.set("what?");   //ERROR, 什么类型都不接受
        System.out.println(t);


        /**
         *  Box<Ticket<String>>里只能放Ticket<String>
         */
        Box<Ticket<String>> boxTstr=new Box<Ticket<String>>();
        boxTstr.set(new Ticket<String>("NoProblem"));
        //boxTstr.set(new Ticket<Integer>(111));    //ERROR,编译器类型检查通不过

        /**
         *  同样,当通配符捕获运行时实际类型后,标记为CAP#1。就什么操作也做不了
         */
        Box<? extends Ticket<?>> boxTstr2=new Box<Ticket<String>>();
        //boxTstr2.set(new Ticket<String>("Now?"));   //ERROR, 什么类型都不接受
        //boxTstr2.set(new Ticket<Integer>(222)); //ERROR, 什么类型都不接受
    }
}

关于通配符第二个例子

下面这个例子基本把通配符常见的使用场景都包括了,遇到问题可以来查一下。

class Holder<T> {
    private T t;
    public void set(T t) { this.t = t; }
    public T get() { return t; }
}

public class Wildcards {
    // 原生类:无泛型,就用Object代替
    static void rawArgs(Holder holder, Object arg) {
        //可以。raw type警告
        holder.set(arg); // raw type Warning:

        // 可以。raw type警告
        holder.set(new Wildcards()); // raw type warning

        // 不行。这里没有泛型T
        //T t = holder.get();

        // 可以。但原先holder里的类型信息丢失。
        Object obj = holder.get();
    }

    // 无边界通配符
    static void unboundedArg(Holder<?> holder, Object arg) {
        //报错。因为Holder<capture of ?> 里的set(capture of ?)方法,代表某种不知道类型的参数,不能接受Object类型,也不接受任何类型。
        //holder.set(arg); // Error:

        //报错。因为Holder<capture of ?> 里的set(capture of ?)方法,代表某种不知道类型的参数,不能接受Object类型,也不接受任何类型。
        //holder.set(new Wildcards()); // Same error

        // 不行,没有泛型T
        //T t = holder.get();

        // 可以。只有Object型可以接受通配符型<?>的赋值。但原先holder里的类型信息丢失。
        Object obj = holder.get();
    }

    // 正常泛型<T>,没问题
    static <T> T exact1(Holder<T> holder) {
        T t = holder.get();
        return t;
    }
    // 正常泛型<T>,没问题
    static <T> T exact2(Holder<T> holder, T arg) {
        holder.set(arg);
        T t = holder.get();
        return t;
    }

    //子类边界
    static <T> T wildSubtype(Holder<? extends T> holder, T arg) {
        //报错。Holder<? extends T> 里的set(? extends T)方法,不能接受T类型
        //holder.set(arg); // Error:

        //可以。holder.get()返回T或T的子类,可以赋值给T类型。
        T t = holder.get();
        return t;
    }

    //超类边界
    static <T> void wildSupertype(Holder<? super T> holder, T arg) {
        //可以。因为set(? super T)接受T或T的超类为参数。无论如何都能接受T类型。
        holder.set(arg);

        //报错。holder.get()返回T或T的超类,无法放进T类型里。
        //T t = holder.get(); // Error:

        // 可以。但原先holder里的类型信息丢失。
        Object obj = holder.get();
    }


    public static void main(String[] args) {
        //Holder raw = new Holder<Long>();
        // Or:
        Long lng = 1L;
        Object o=new Object();

        //四种不同程度泛化的Holder对象
        Holder raw = new Holder();
        Holder<Long> qualified = new Holder<Long>();
        Holder<?> unbounded = new Holder<Long>();
        Holder<? extends Long> bounded = new Holder<Long>();

        //原生类Holder为参数:四种Holder放进去都没问题
        rawArgs(raw, lng);
        rawArgs(qualified, lng);
        rawArgs(unbounded, lng);
        rawArgs(bounded, lng);

        //无边界通配符Holder:无论放什么都不行,编译期已经报错
        unboundedArg(raw, lng);
        unboundedArg(qualified, lng);
        unboundedArg(unbounded, lng);
        unboundedArg(bounded, lng);

        //警告:用Holder当Holder<T>类型参数
        Object r1 = exact1(raw); // Warnings: unchecked

        //没问题
        Long r2 = exact1(qualified);

        //只有Object可以接受<?>通配符的返回类型
        Object r3 = exact1(unbounded); // Must return Object

        //没问题
        Long r4 = exact1(bounded);

        //警告:用Holder当Holder<Long>
        Long r5 = exact2(raw, lng); // Warnings: unchecked

        //没问题
        Long r6 = exact2(qualified, lng);

        //报错:exact2(Holder<T>,T)方法不能用(Holder<capture of ?>,Long)这两个参数。
        Long r7 = exact2(unbounded, lng); // Error:

        //报错:exact2(Holder<T>,T)方法不能用(Holder<capture of ? extends Long>,Long)这两个参数。
        Long r8 = exact2(bounded, lng); // Error:

        //警告:改用holder<Long>的地方用了holder原生类
        Long r9 = wildSubtype(raw, lng); // Warnings: unchecked

        //警告:该给(Holder<? extends T>,T)参数的,给了(Holder,Long)
        Long r10 = wildSubtype(qualified, lng);

        //没问题,但只能用Object来接收返回值
        Object r11 = wildSubtype(unbounded, lng);

        //没问题
        Long r12 = wildSubtype(bounded, lng);

        //警告:该给(Holder<? super T>,T)参数的,给了(Holder,Long)
        wildSupertype(raw, lng); // Warnings:

        //没问题
        wildSupertype(qualified, lng);

        //报错:该给(Holder<? super T>,T)参数的,给了(Holder<capture of ?>,Long)
        wildSupertype(unbounded, lng); // Error:

        //报错:该给(Holder<? super T>,T)参数的,给了(Holder<capture of ? extends Long>,Long)
        wildSupertype(bounded, lng); // Error:

    }
}

无界通配符的第三个例子

使用一个泛型类Plate<T>,如果用无界通配符Plate<?>,就可以放各种不同的类型。每存入一个类型,都会临时命名为CAP#XXX。

所以List<Plate<?>>里什么Plate都能放。

interface Fruit{public String toString();}
class Apple implements Fruit{public String toString(){return "Apple!";}}
class Banana implements Fruit{public String toString(){return "Banana!";}}
class Melon implements Fruit{public String toString(){return "Melon!";}}

class Plate<T>{
    private T item;
    public Plate(T t){item=t;}
    public String toString(){return "A plate of "+item;}
}

public class WildBox<T>{
    private List<T> list=new ArrayList<T>();

    public void add(T t){list.add(t);}
    public T get(int index){return (index<list.size())? list.get(index):null;}

    public static void main(String[] args){
        WildBox<Plate<?>> wb=new WildBox<Plate<?>>();
        wb.add(new Plate<Apple>(new Apple()));
        wb.add(new Plate<Banana>(new Banana()));

        System.out.println(wb.get(0));
        System.out.println(wb.get(1));
    }
}

//Output:
//A plate of Apple!
//A plate of Banana!

但判断Set<Plate<?>>里都有什么Plate,都是false。体会一下通配符的捕获机制。

interface Fruit{public String toString();}
class Apple implements Fruit{public String toString(){return "Apple!";}}
class Banana implements Fruit{public String toString(){return "Banana!";}}
class Melon implements Fruit{public String toString(){return "Melon!";}}

class Plate<T>{
    private T item;
    public Plate(T t){item=t;}
    public String toString(){return "A plate of "+item;}
}

public class WildBox2<T>{
    private Set<T> set=new HashSet<T>();

    public void add(T t){set.add(t);}
    public boolean contains(T t){return set.contains(t);}

    public static void main(String[] args){
        WildBox2<Plate<?>> wb=new WildBox2<Plate<?>>();
        wb.add(new Plate<Apple>(new Apple()));
        wb.add(new Plate<Banana>(new Banana()));

        System.out.println(wb.contains(new Plate<Apple>(new Apple())));
        System.out.println(wb.contains(new Plate<Banana>(new Banana())));
        System.out.println(wb.contains(new Plate<Melon>(new Melon())));
    }
}

协变和自限定

协变

根据Override重写的规则,被重写方法的参数和返回值都不能变。

Java 5.0开始允许在派生类中继承自基类的方法改变返回值。

class Base {}
class Derived extends Base {}

interface OrdinaryGetter {
    Base get();
}
interface DerivedGetter extends OrdinaryGetter {
    // Return type of overridden method is allowed to vary:
    Derived get();
}

古怪的循环泛型(CRG)

古怪的循环泛型”的本质就是:“基类用导出类作为类型参数”。

class BaseGeneric<T> {}
class SubType extends BaseGeneric<SubType> {}

这种循环泛型的好处是,泛型基类BaseGeneric里定义的方法,是以其自身的导出类SubType为参数,和返回值。所以SubType类所继承的方法都是以同类SubType的其他对象实例为参数和返回值。所以,泛型基类BaseGeneric相当于定义了针对它自身导出类的一系列操作。然后它的导出类就只能操作自己的同类对象。这是循环泛型的意义所在。

自限定

但上面的例子只是说SubType使用了循环泛型的用法。但泛型基类BaseGeneric的其他子类完全可以不使用循环泛型。

所以自限定的意义就在于,在定义泛型基类的时候,强制这个泛型基类的导出类,只能使用循环泛型的形式。

class SelfBounds<T extends SelfBounds<T>> {}

自限定类型最典型的应用:Enum枚举型 一定要看这篇关于枚举型的文章–《Java 语言中 Enum 类型的使用介绍》

自限定自带协变特性

Getter g的g.get()方法的返回值是派生类Getter类型,而不是基类GenericGetter类型。而且和普通的继承规则不同,g.get()方法不是被重载(overload)而是重写(override)。

interface GenericGetter<T extends GenericGetter<T>> {
    T get();
}

interface Getter extends GenericGetter<Getter> {}

public class GenericsAndReturnTypes {
    void test(Getter g) {
        Getter result = g.get();
        GenericGetter gg = g.get(); // Also the base type
    }
}

异常

想要抛出根据泛型变化的异常,就需要把异常当成类型参数写进函数里。然后由throws关键字抛出。看下面这个例子:

interface Processor<T,E extends Exception, F extends Exception> {
    public void process(List<T> resultCollector) throws E,F;
}

class ProcessRunner<T,E extends Exception, F extends Exception> extends ArrayList<Processor<T,E,F>> {
    private static final long serialVersionUID=0;
    public List<T> processAll() throws E,F {
        List<T> resultCollector = new ArrayList<T>();
        for(Processor<T,E,F> processor : this){
            processor.process(resultCollector);
        }
        return resultCollector;
    }
}

Java缺乏“潜在类型”机制

C++和Python都支持“潜在类型”机制

潜在类型机制也叫“鸭子类型机制”。大白话说就是:我不用定义一个关于方法a()和方法b()的接口。我可以不关心类型,只要有a()方法和b()方法就行。

Python里可以有这样的代码:

class Dog:
	def speak(self):
		print "Arf!"
	def sit(self):
		print "Sitting"
	def reproduce(self):
		pass

class Robot:
	def speak(self):
		print "Click!"
	def sit(self):
		print "Clank!"
	def oilChange(self) :
		pass

def perform(anything):
	anything.speak()
	anything.sit()

C++里可以这样写:

class Dog {
	public:
	void speak() {}
	void sit() {}
	void reproduce() {}
};

class Robot {
	public:
	void speak() {}
	void sit() {}
	void oilChange() {
};

template<class T> void perform(T anything) {
	anything.speak();
	anything.sit();
}

用适配器模式模拟“潜在类型”

Java泛型的先天不足,可以用模式来弥补。下面的例子用适配器模式,模拟出一个“潜在类型”。

//addable接口
interface Addable<T> { void add(T t); }

//面向Addable接口的fill方法
class FillPets {
    //用反射填充容器
    public static <T extends Pet> void fill(Addable<T> addable, Class<? extends T> classToken, int size) {
        for(int i = 0; i < size; i++){
            try {
                addable.add(classToken.newInstance());
            } catch(Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
}

/** 《适配器》
 * 原理是类库里的Collection和SimpleQueue动不了。
 * 那就给他们都套一层代理。然后新的代理类实现Addable接口。
 */

//Collection是通过组合的方式套代理
class AddableCollectionAdapter<T> implements Addable<T> {
    private Collection<T> c;
    public AddableCollectionAdapter(Collection<T> c) {
        this.c = c;
    }
    public void add(T item) { c.add(item); }
}

// 把加了add()方法的容器的引用,赋值给Addable接口。
class Adapter {
    public static <T> Addable<T> collectionAdapter(Collection<T> c) {
        return new AddableCollectionAdapter<T>(c);
    }
}

//SimpleQueue
class SimpleQueue<T> implements Iterable<T> {
    private LinkedList<T> storage = new LinkedList<T>();
    public void add(T t) { storage.offer(t); }
    public T get() { return storage.poll(); }
    public Iterator<T> iterator() {
        return storage.iterator();
    }
}

//SimpleQueue的派生类实现Addable接口。
class AddableSimpleQueue<T> extends SimpleQueue<T> implements Addable<T> {
    public void add(T item) { super.add(item); }
}

/**
 *  LEV 1
 */
class Individual{
    private String name;
    public Individual(){this.name="NULL";}
    public Individual(String name){this.name=name;}
    public void speak(){System.out.println("...");}
}

/**
 *  LEV 2
 */
class Person extends Individual {
    public Person(String name) { super(name); }
    @Override
    public void speak(){System.out.println("Hello World!");}
}

class Pet extends Individual {
    public Pet(String name) { super(name); }
    public Pet() { super(); }
    @Override
    public void speak(){System.out.println("!!!");}
}

/**
 *  LEV 3 - 狗,猫,鼠
 */
class Dog extends Pet {
    public Dog(String name) { super(name); }
    public Dog() { super(); }
    @Override
    public void speak(){System.out.println("WongWong!!!");}
}

class Cat extends Pet {
    public Cat(String name) { super(name); }
    public Cat() { super(); }
    @Override
    public void speak(){System.out.println("MiewMiew!!!");}
}

class Rodent extends Pet {
    public Rodent(String name) { super(name); }
    public Rodent() { super(); }
    @Override
    public void speak(){System.out.println("JiJiJi!!!");}
}

/**
 *  LEV 4 - 狗系
 */
class Mutt extends Dog {
    public Mutt(String name) { super(name); }
    public Mutt() { super(); }
}

class Pug extends Dog {
    public Pug(String name) { super(name); }
    public Pug() { super(); }
}

/**
 *  LEV 4 - 猫系
 */
class EgyptianMau extends Cat {
    public EgyptianMau(String name) { super(name); }
    public EgyptianMau() { super(); }
}

class Manx extends Cat {
    public Manx(String name) { super(name); }
    public Manx() { super(); }
}

/**
 *  LEV 4 - 鼠系
 */
class Rat extends Rodent {
    public Rat(String name) { super(name); }
    public Rat() { super(); }
}

class Mouse extends Rodent {
    public Mouse(String name) { super(name); }
    public Mouse() { super(); }
}

class Hamster extends Rodent {
    public Hamster(String name) { super(name); }
    public Hamster() { super(); }
}

 *  测试类
 */
public class Exercise41{
    public static void main(String[] args){
        //Pet容器
        List<Dog> dogs=new ArrayList<Dog>();
        //给Pet容器套上实现了Addable接口的适配器,就能用面向Addable接口的fill()方法了。
        Fill2.fill(new AddableCollectionAdapter<Dog>(dogs),Mutt.class, 3);
        //用辅助方法获得Addable接口对象实例
        Fill2.fill(Adapter.collectionAdapter(dogs), Pug.class, 2);
        for(Dog d: dogs){
            d.speak();
        }
        System.out.println("----------------------");

        //SimpleQueue实现了Addable()接口与的派生类。也可以用fill()方法填充。
        AddableSimpleQueue<Cat> catQueue = new AddableSimpleQueue<Cat>();
        Fill2.fill(catQueue, EgyptianMau.class, 4);
        Fill2.fill(catQueue, Manx.class, 1);
        for(Cat c: catQueue){
            c.speak();
        }
    }
}

最佳实践

记住

思考

练习

Exercise 1

Pet.java
package com.ciaoshen.thinkinjava.chapter15;
import java.util.*;
class Pet{public String toString(){return "A Pet!";}}
Dog.java
package com.ciaoshen.thinkinjava.chapter15;
import java.util.*;
class Dog extends Pet{public String toString(){return "A Dog!";}}
Cat.java
package com.ciaoshen.thinkinjava.chapter15;
import java.util.*;
class Cat extends Pet{public String toString(){return "A Cat!";}}
Exercise1.java
package com.ciaoshen.thinkinjava.chapter15;
import java.util.*;

public class Exercise1<T>{
    private T t1;
    private T t2;
    private T t3;

    public Exercise1(T one,T two,T three){t1=one;t2=two;t3=three;}
    public List<T> get(){
        return Arrays.asList(t1,t2,t3);
    }
    public String toString(){return "["+t1.toString()+"],"+"["+t2.toString()+"],"+"["+t3.toString()+"]";}

    public static void main(String[] args){
        Pet p=new Pet();
        Dog d=new Dog();
        Cat c=new Cat();
        Exercise1<Pet> h=new Exercise1<Pet>(p,d,c);
        System.out.println(h);
        List<Pet> l=h.get();
        for(int i=0;i<l.size();i++){
            System.out.println(l.get(i));
        }
    }
}

Exercise 2

Pet.java
package com.ciaoshen.thinkinjava.chapter15;
import java.util.*;
class Pet{public String toString(){return "A Pet!";}}
Dog.java
package com.ciaoshen.thinkinjava.chapter15;
import java.util.*;
class Dog extends Pet{public String toString(){return "A Dog!";}}
Cat.java
package com.ciaoshen.thinkinjava.chapter15;
import java.util.*;
class Cat extends Pet{public String toString(){return "A Cat!";}}
Exercise2.java
package com.ciaoshen.thinkinjava.chapter15;
import java.util.*;

public class Exercise2<T>{

    private T t1;
    private T t2;
    private T t3;

    public Exercise2(T one,T two,T three){t1=one;t2=two;t3=three;}
    public List<T> get(){
        return Arrays.asList(t1,t2,t3);
    }
    public String toString(){return "["+t1.toString()+"],"+"["+t2.toString()+"],"+"["+t3.toString()+"]";}

    public static void main(String[] args){
        Pet p=new Pet();
        Dog d=new Dog();
        Cat c=new Cat();
        Exercise2<Pet> h=new Exercise2<Pet>(p,d,c);
        System.out.println(h);
        List<Pet> l=h.get();
        for(int i=0;i<l.size();i++){
            System.out.println(l.get(i));
        }
    }
}

Exercise 3

class Exercise3<A,B,C,D,E,F>{ A a; B b; C c; D d; E e; F f;

public Exercise3(A inA,B inB,C inC,D inD,E inE,F inF){a=inA;b=inB;c=inC;d=inD;e=inE;f=inF;}

public String toString(){return a.toString()+b.toString()+c.toString()+d.toString()+e.toString()+f.toString();}

public static void main(String[] args){
    Exercise3<Integer,Long,Float,Double,String,Boolean> mySix=new Exercise3<Integer,Long,Float,Double,String,Boolean>(1,2l,3f,4d,"five",true);
    System.out.println(mySix.toString());
} } ```

Exercise 4

Selector.java
package com.ciaoshen.thinkinjava.chapter15;

public interface Selector<T> {
    boolean end();
    T current();
    void next();
}
Exercise4.java
package com.ciaoshen.thinkinjava.chapter15;
import java.util.*;

public class Exercise4<T> {
    private List<T> items;
    private int next = 0;

    public Exercise4() { items = new ArrayList<T>(); }

    public void add(T x) {
        items.add(x);
    }

    public String toString(){
        String r="";
        for(T item : items){
            r+=item;
        }
        return r;
    }

    private class SequenceSelector implements Selector<T> {
        private int i = 0;
        public boolean end() { return i == items.size(); }
        public T current() { return items.get(i); }
        public void next() { if(i < items.size()){i++;} }
    }

    public Selector<T> selector() {
        return new SequenceSelector();
    }

    public static void main(String[] args) {
        Exercise4<String> sequence = new Exercise4<String>();
        for(int i = 0; i < 10; i++){
            sequence.add(Integer.toString(i));
        }
        System.out.println(sequence);

        Selector<String> selector = sequence.selector();
        while(!selector.end()) {
            System.out.print(selector.current() + " ");
            selector.next();
        }
    }
}

Exercise 5

package com.ciaoshen.thinkinjava.chapter15;
import java.util.*;

public class Exercise5<T> {

    private class Node {
        T item;
        Node next;
        Node() { item = null; next = null; }
        Node(T item, Node next) {
            this.item = item;
            this.next = next;
        }
        boolean end() { return item == null && next == null; }
    }

    private Node top = new Node(); // End sentinel

    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) {
        Exercise5<String> test= new Exercise5<String>();
        for(String s : "Phasers on stun!".split(" ")){
            test.push(s);
        }
        String s;
        while((s=test.pop()) != null){
            System.out.println(s);
        }
    }
}

Exercise 6

package com.ciaoshen.thinkinjava.chapter15;
import java.util.*;

public class Exercise6<T> {
    private ArrayList<T> storage = new ArrayList<T>();
    private Random rand = new Random();
    public void add(T item) { storage.add(item); }
    public T select() {
        return storage.get(rand.nextInt(storage.size()));
    }

    public static void main(String[] args) {
        Exercise6<String> rs = new Exercise6<String>();
        Exercise6<Integer> ri=new Exercise6<Integer>();
        Exercise6<Float> rf=new Exercise6<Float>();
        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() + " ");
        }
        for(int i=0;i<10;i++){
            ri.add(i);
            rf.add((float)i);
        }
        for(int i=0;i<10;i++){
            System.out.println(ri.select());
            System.out.println(rf.select());
        }
    }
}

Exercise 7

这题的关键在于实现两个接口。外部类IterableFibonacci实现Iterable接口,内部类FibIte实现Iterator接口。

Fibonacci.java
package com.ciaoshen.thinkinjava.chapter15;
import java.util.*;

public class Fibonacci{
    public Integer next() { return fib(count++); }
    private int count = 0;
    private int fib(int n) {
        if(n < 2) return 1;
        return fib(n-2) + fib(n-1);
    }
}
Exercise7.java
package com.ciaoshen.thinkinjava.chapter15;
import java.util.*;

public class Exercise7 extends Fibonacci implements Iterable<Integer>{
    private int n;
    public Exercise7(int count) { n = count; }
    public Iterator<Integer> iterator(){return this.new FibIte();}

    class FibIte implements Iterator<Integer>{
        private int count=0;
        public boolean hasNext() { return n > 0; }
        public Integer next() {
            n--;
            return Exercise7.this.next();
        }
        public void remove() { // Not implemented
            throw new UnsupportedOperationException();
        }
    }
    public static void main(String[] args) {
        Exercise7 iteFib=new Exercise7(18);
        Iterator<Integer> ite=iteFib.iterator();
        while(ite.hasNext()){
            System.out.print(ite.next()+" ");
        }
        System.out.println();
    }
}

Exercise 8

Generator.java
package com.ciaoshen.thinkinjava.chapter15;

public interface Generator<T>{
    public T next();
}
GoodGuys.java
package com.ciaoshen.thinkinjava.chapter15;

public class GoodGuys extends StoryCharacters{
    public GoodGuys(){
        super("Good "+String.valueOf(System.nanoTime()));
    }
}
BadGuys.java
package com.ciaoshen.thinkinjava.chapter15;

public class BadGuys extends StoryCharacters{
    public BadGuys(){
        super("Bad "+String.valueOf(System.nanoTime()));
    }
}
StoryCharacters.java
package com.ciaoshen.thinkinjava.chapter15;

public class StoryCharacters{
    public String name;
    public StoryCharacters(String inName){name=inName;}
    public String toString(){return name;}
}
Exercise8.java
package com.ciaoshen.thinkinjava.chapter15;
import java.util.*;

public class Exercise8 implements Generator<StoryCharacters>, Iterable<StoryCharacters> {
    private static List<Class<? extends StoryCharacters>> factories=new ArrayList<Class<? extends StoryCharacters>>();
    private static Random rand=new Random();
    static{
        factories.add(GoodGuys.class);
        factories.add(BadGuys.class);
    }
    private int max;
    public Exercise8(int inNum){max=inNum;}
    public Iterator<StoryCharacters> iterator(){return this.new ChIte(max);}
    public StoryCharacters next(){
        try{
            return (StoryCharacters)(factories.get(rand.nextInt(factories.size())).newInstance());
        }catch(Exception e){
            System.out.println("Cannot make the new instance of StoryCharacters!");
            return null;
        }
    }

    class ChIte implements Iterator<StoryCharacters>{
        private int n;
        public ChIte(int num){n=num;}
        public boolean hasNext(){return n>0;}
        public StoryCharacters next(){
            n--;
            return Exercise8.this.next();
        }
        public void remove(){
            throw new UnsupportedOperationException();
        }
    }

    public static void main(String[] args) {
        Exercise8 test=new Exercise8(10);
        Iterator<StoryCharacters> ite=test.iterator();
        while(ite.hasNext()){
            System.out.println(ite.next());
        }
    }
}

Exercise 9

package com.ciaoshen.thinkinjava.chapter15;
import java.util.*;

public class Exercise9{
    public <T,U,V> void f(T t, U u, V v) {
        System.out.println(t.getClass().getName());
        System.out.println(u.getClass().getName());
        System.out.println(v.getClass().getName());
    }
    public static void main(String[] args) {
        Exercise9 test= new Exercise9();
        test.f("",1,1.0);
    }
}

Exercise 10

package com.ciaoshen.thinkinjava.chapter15;
import java.util.*;

public class Exercise10{
    public <T,U> void f(T t, U u, String s) {
        System.out.println(t.getClass().getName());
        System.out.println(u.getClass().getName());
        System.out.println(s.getClass().getName());
    }
    public static void main(String[] args) {
        Exercise10 test= new Exercise10();
        test.f(1,1.0,"2.0");
    }
}

Exercise 11

GenericOne.java
package com.ciaoshen.thinkinjava.chapter15;
import java.util.*;

public class GenericOne<T>{
    private T t;
    public GenericOne(T inT){t=inT;}
    public String toString(){return t.toString()+": "+ t.getClass().getName();}
}
Exercise11.java
package com.ciaoshen.thinkinjava.chapter15;
import java.util.*;

public class Exercise11{
    public static <T> GenericOne<T> getOne(T inT){return new GenericOne<T>(inT);}

    public static void main(String[] args){
        GenericOne<String> go= Exercise11.getOne("Hello");
        System.out.println(go);
        GenericOne<Integer> gi = Exercise11.getOne(100);
        System.out.println(gi);
    }
}

Exercise 12

GenericOne.java
package com.ciaoshen.thinkinjava.chapter15;
import java.util.*;

public class GenericOne<T>{
    private T t;
    public GenericOne(T inT){t=inT;}
    public String toString(){return t.toString()+": "+ t.getClass().getName();}
}
Exercise12.java
package com.ciaoshen.thinkinjava.chapter15;
import java.util.*;

public class Exercise12{
    public static <T> GenericOne<T> getOne(T inT){return new GenericOne<T>(inT);}

    public static void main(String[] args){
        GenericOne<String> go= Exercise12.<String>getOne("Hello");
        System.out.println(go);
        GenericOne<Integer> gi = Exercise12.<Integer>getOne(100);
        System.out.println(gi);
    }
}

Exercise 13

Generator.java
package com.ciaoshen.thinkinjava.chapter15;

public interface Generator<T>{
    public T next();
}
Coffee.java
package com.ciaoshen.thinkinjava.chapter15;

public class Coffee{
    private static long count;
    private long id;
    public Coffee(){id=count++;}
    public long showId(){return id;}
}
Latte.java
package com.ciaoshen.thinkinjava.chapter15;

public class Latte extends Coffee{
    public String toString(){return "No."+String.valueOf(showId())+">>> I am Latte!";}
}
Mocha.java
package com.ciaoshen.thinkinjava.chapter15;

public class Mocha extends Coffee{
    public String toString(){return "No."+String.valueOf(showId())+">>> I am Mocha!";}
}
Capuccino.java
package com.ciaoshen.thinkinjava.chapter15;

public class Capuccino extends Coffee{
    public String toString(){return "No."+String.valueOf(showId())+">>> I am Capuccino!";}
}
CoffeeGnerator.java
package com.ciaoshen.thinkinjava.chapter15;
import java.util.*;

public class CoffeeGenerator implements Generator<Coffee>{
    private static List<Class<? extends Coffee>> c=new ArrayList<Class<? extends Coffee>>();
    static{
        c.add(Latte.class);
        c.add(Mocha.class);
        c.add(Capuccino.class);
    }
    private Random rand=new Random();
    public Coffee next(){
        int i=rand.nextInt(c.size());
        try{
            return c.get(i).newInstance();
        }catch(Exception e){
            System.out.println(e);
            return null;
        }
    }
}
Exercise13.java
package com.ciaoshen.thinkinjava.chapter15;
import java.util.*;

public class Exercise13{
    public static <T> Collection<T> fill(Collection<T> coll, Generator<T> gen, int n) {
        for(int i = 0; i < n; i++){
            coll.add(gen.next());
        }
        return coll;
    }
    public static <T> List<T> fill(List<T> list, Generator<T> gen, int n){
        for(int i=0;i<n;i++){
            list.add(gen.next());
        }
        return list;
    }
    public static <T> Queue<T> fill(Queue<T> queue, Generator<T> gen, int n){
        for(int i=0;i<n;i++){
            queue.add(gen.next());
        }
        return queue;
    }
    public static <T> Set<T> fill(Set<T> set, Generator<T> gen, int n){
        for(int i=0;i<n;i++){
            set.add(gen.next());
        }
        return set;
    }

    public static void main(String[] args) {
        List<Coffee> manyCoffee=new ArrayList<Coffee>();
        manyCoffee=Exercise13.fill(manyCoffee, new CoffeeGenerator(), 10);
        for(Coffee cup : manyCoffee){
            System.out.println(cup);
        }
    }
}

Exercise 14

Generator.java
package com.ciaoshen.thinkinjava.chapter15;

public interface Generator<T>{
    public T next();
}
CountedObject.java
package com.ciaoshen.thinkinjava.chapter15;

public class CountedObject {
    private static long counter = 0;
    private final long id = counter++;
    public long id() { return id; }
    public String toString() { return "CountedObject " + id;}
}
BasicGenerator.java
package com.ciaoshen.thinkinjava.chapter15;

public class BasicGenerator<T> implements Generator<T> {
    private Class<T> type;

    public BasicGenerator(Class<T> type){ this.type = type; }
    public T next() {
        try {
            // Assumes type is a public class:
            return type.newInstance();
        } catch(Exception e) {
            throw new RuntimeException(e);
        }
    }
    // Produce a Default generator given a type token:
    public static <T> Generator<T> create(Class<T> type) {
        return new BasicGenerator<T>(type);
    }
}
Exercise14.java
package com.ciaoshen.thinkinjava.chapter15;

public class Exercise14{
    public static void main(String[] args) {
        BasicGenerator<CountedObject> bg=new BasicGenerator<CountedObject>(CountedObject.class);
        for(int i = 0; i < 5; i++)
            System.out.println(bg.next());
    }
}

Exercise 15

TwoTuple.java
package com.ciaoshen.thinkinjava.chapter15;

public class TwoTuple<A,B>{
    private final A first;
    private final B second;
    public TwoTuple(A a,B b){first=a;second=b;}
    public String toString(){return "["+first+","+second+"]";}
}
ThreeTuple.java
package com.ciaoshen.thinkinjava.chapter15;

public class ThreeTuple<A,B,C>{
    private final A first;
    private final B second;
    private final C third;
    public ThreeTuple(A a,B b,C c){first=a;second=b;third=c;}
    public String toString(){return "["+first+","+second+","+third+"]";}
}
FourTuple.java
package com.ciaoshen.thinkinjava.chapter15;

public class FourTuple<A,B,C,D>{
    private final A first;
    private final B second;
    private final C third;
    private final D fourth;
    public FourTuple(A a,B b,C c,D d){first=a;second=b;third=c;fourth=d;}
    public String toString(){return "["+first+","+second+","+third+","+fourth+"]";}
}
FiveTuple.java
package com.ciaoshen.thinkinjava.chapter15;

public class FiveTuple<A,B,C,D,E>{
    private final A first;
    private final B second;
    private final C third;
    private final D fourth;
    private final E fifth;
    public FiveTuple(A a,B b,C c,D d,E e){first=a;second=b;third=c;fourth=d;fifth=e;}
    public String toString(){return "["+first+","+second+","+third+","+fourth+","+fifth+"]";}
}
SixTuple.java
package com.ciaoshen.thinkinjava.chapter15;

public class SixTuple<A,B,C,D,E,F>{
    private final A first;
    private final B second;
    private final C third;
    private final D fourth;
    private final E fifth;
    private final F sixth;
    public FiveTuple(A a,B b,C c,D d,E e,F f){first=a;second=b;third=c;fourth=d;fifth=e;sixth=f;}
    public String toString(){return "["+first+","+second+","+third+","+fourth+","+fifth+","+sixth+"]";}
}
Tuple.java
package com.ciaoshen.thinkinjava.chapter15;

public class Tuple{
    public static <A,B> TwoTuple<A,B> tuple(A a, B b) {
        return new TwoTuple<A,B>(a, b);
    }
    public static <A,B,C> ThreeTuple<A,B,C> tuple(A a, B b, C c) {
        return new ThreeTuple<A,B,C>(a, b, c);
    }
    public static <A,B,C,D> FourTuple<A,B,C,D> tuple(A a, B b, C c, D d) {
        return new FourTuple<A,B,C,D>(a, b, c, d);
    }
    public static <A,B,C,D,E> FiveTuple<A,B,C,D,E> tuple(A a, B b, C c, D d, E e) {
        return new FiveTuple<A,B,C,D,E>(a, b, c, d, e);
    }
    public static <A,B,C,D,E,F> SixTuple<A,B,C,D,E,F> tuple(A a, B b, C c, D d, E e, F f) {
        return new SixTuple<A,B,C,D,E,F>(a, b, c, d, e, f);
    }
}
Exercise15.java
package com.ciaoshen.thinkinjava.chapter15;

public class Exercise15{
    public static void main(String[] args){
        @SuppressWarnings("rawtypes")
        TwoTuple tuple=Tuple.tuple("ABC",123);
        System.out.println(tuple);
        //@SuppressWarnings("unchecked")    //不加注释就会报unchecked警告
        TwoTuple<String,Integer> withType=tuple;
        System.out.println(withType);
    }
}

Exercise 16

TwoTuple.java
package com.ciaoshen.thinkinjava.chapter15;

public class TwoTuple<A,B>{
    private final A first;
    private final B second;
    public TwoTuple(A a,B b){first=a;second=b;}
    public String toString(){return "["+first+","+second+"]";}
}
ThreeTuple.java
package com.ciaoshen.thinkinjava.chapter15;

public class ThreeTuple<A,B,C>{
    private final A first;
    private final B second;
    private final C third;
    public ThreeTuple(A a,B b,C c){first=a;second=b;third=c;}
    public String toString(){return "["+first+","+second+","+third+"]";}
}
FourTuple.java
package com.ciaoshen.thinkinjava.chapter15;

public class FourTuple<A,B,C,D>{
    private final A first;
    private final B second;
    private final C third;
    private final D fourth;
    public FourTuple(A a,B b,C c,D d){first=a;second=b;third=c;fourth=d;}
    public String toString(){return "["+first+","+second+","+third+","+fourth+"]";}
}
FiveTuple.java
package com.ciaoshen.thinkinjava.chapter15;

public class FiveTuple<A,B,C,D,E>{
    private final A first;
    private final B second;
    private final C third;
    private final D fourth;
    private final E fifth;
    public FiveTuple(A a,B b,C c,D d,E e){first=a;second=b;third=c;fourth=d;fifth=e;}
    public String toString(){return "["+first+","+second+","+third+","+fourth+","+fifth+"]";}
}
SixTuple.java
package com.ciaoshen.thinkinjava.chapter15;

public class SixTuple<A,B,C,D,E,F>{
    private final A first;
    private final B second;
    private final C third;
    private final D fourth;
    private final E fifth;
    private final F sixth;
    public FiveTuple(A a,B b,C c,D d,E e,F f){first=a;second=b;third=c;fourth=d;fifth=e;sixth=f;}
    public String toString(){return "["+first+","+second+","+third+","+fourth+","+fifth+","+sixth+"]";}
}
Tuple.java
package com.ciaoshen.thinkinjava.chapter15;

public class Tuple{
    public static <A,B> TwoTuple<A,B> tuple(A a, B b) {
        return new TwoTuple<A,B>(a, b);
    }
    public static <A,B,C> ThreeTuple<A,B,C> tuple(A a, B b, C c) {
        return new ThreeTuple<A,B,C>(a, b, c);
    }
    public static <A,B,C,D> FourTuple<A,B,C,D> tuple(A a, B b, C c, D d) {
        return new FourTuple<A,B,C,D>(a, b, c, d);
    }
    public static <A,B,C,D,E> FiveTuple<A,B,C,D,E> tuple(A a, B b, C c, D d, E e) {
        return new FiveTuple<A,B,C,D,E>(a, b, c, d, e);
    }
    public static <A,B,C,D,E,F> SixTuple<A,B,C,D,E,F> tuple(A a, B b, C c, D d, E e, F f) {
        return new SixTuple<A,B,C,D,E,F>(a, b, c, d, e, f);
    }
}
Vehicle.java
package com.ciaoshen.thinkinjava.chapter15;

public class Vehicle{
    private static int count=0;
    private int id=++count;
    public String toString(){return "Vehicle#"+id;}
}
Amphibian.java
package com.ciaoshen.thinkinjava.chapter15;

public class Amphibian{
    private static int count=0;
    private int id=++count;
    public String toString(){return "Amphibian#"+id;}
}
Exercise16.java
package com.ciaoshen.thinkinjava.chapter15;

public class Exercise16{
    static TwoTuple<String,Integer> f() {
        return Tuple.tuple("hi", 47);
    }
    @SuppressWarnings("rawtypes")
    static TwoTuple f2() { return Tuple.tuple("hi", 47); }
    static ThreeTuple<Amphibian,String,Integer> g() {
        return Tuple.tuple(new Amphibian(), "hi", 47);
    }
    static FourTuple<Vehicle,Amphibian,String,Integer> h() {
        return Tuple.tuple(new Vehicle(), new Amphibian(), "hi", 47);
    }
    static FiveTuple<Vehicle,Amphibian,String,Integer,Double> k() {
        return Tuple.tuple(new Vehicle(), new Amphibian(), "hi", 47, 11.1);
    }
    static SixTuple<Vehicle,Amphibian,String,Integer,Double,Float> l() {
        return Tuple.tuple(new Vehicle(), new Amphibian(), "hi", 47, 11.1,22.2f);
    }
    public static void main(String[] args) {
        TwoTuple<String,Integer> ttsi = f();
        System.out.println(ttsi);
        System.out.println(f2());
        System.out.println(g());
        System.out.println(h());
        System.out.println(k());
        System.out.println(l());
    }
}

Exercise 17

这道题关键是练习泛型方法怎么声明:

**public static <T extends Enum> EnumSet union(EnumSet a, EnumSet b) {... ...}**

注意! 在函数的参数以及返回值的地方直接用泛型替换符T来表示,但是在最前面参数列表的地方,要定义参数T的具体边界。

package com.ciaoshen.thinkinjava.chapter15;
import java.util.*;
import java.lang.reflect.*;

public class Exercise17 {

    private static enum Watercolors { ZINC, LEMON_YELLOW, MEDIUM_YELLOW, DEEP_YELLOW, ORANGE, BRILLIANT_RED, CRIMSON, MAGENTA, ROSE_MADDER, VIOLET, CERULEAN_BLUE_HUE, PHTHALO_BLUE, ULTRAMARINE, COBALT_BLUE_HUE, PERMANENT_GREEN, VIRIDIAN_HUE, SAP_GREEN, YELLOW_OCHRE, BURNT_SIENNA, RAW_UMBER, BURNT_UMBER, PAYNES_GRAY, IVORY_BLACK }
    public static <T extends Enum<T>> EnumSet<T> union(EnumSet<T> a, EnumSet<T> b) {
        EnumSet<T> result = a.clone();
        result.addAll(b);
        return result;
    }
    public static <T extends Enum<T>> EnumSet<T> intersection(EnumSet<T> a, EnumSet<T> b) {
        EnumSet<T> result = a.clone();
        result.retainAll(b);
        return result;
    }
    public static <T extends Enum<T>> EnumSet<T> difference(EnumSet<T> superset, EnumSet<T> subset) {
        EnumSet<T> result = superset.clone();
        result.removeAll(subset);
        return result;
    }
    public static <T extends Enum<T>> EnumSet<T> complement(EnumSet<T> a, EnumSet<T> b) {
        return difference(union(a, b), intersection(a, b));
    }
    public static void main(String[] args){
        EnumSet<Watercolors> set1=EnumSet.range(Watercolors.MEDIUM_YELLOW, Watercolors.MAGENTA);
        EnumSet<Watercolors> set2=EnumSet.range(Watercolors.ZINC,Watercolors.ORANGE);
        EnumSet<Watercolors> setUnion=Sets.union(set1,set2);
        EnumSet<Watercolors> setIntersection=Sets.intersection(set1,set2);
        EnumSet<Watercolors> setComplement=Sets.complement(set1,set2);
        EnumSet<Watercolors> superset=EnumSet.range(Watercolors.ZINC,Watercolors.PERMANENT_GREEN);
        EnumSet<Watercolors> subset=EnumSet.range(Watercolors.CRIMSON, Watercolors.ULTRAMARINE);
        EnumSet<Watercolors> setDifference=Sets.difference(superset,subset);
        System.out.println("\n Set Union >>>>>");
        for(Watercolors w : setUnion){
            System.out.print(w+"    ");
        }
        System.out.println("\n Set Intersection >>>>>");
        for(Watercolors w : setIntersection){
            System.out.print(w+"    ");
        }
        System.out.println("\n Set Complement >>>>>");
        for(Watercolors w : setComplement){
            System.out.print(w+"    ");
        }
        System.out.println("\n Set Difference >>>>>");
        for(Watercolors w : setDifference){
            System.out.print(w+"    ");
        }
    }
}

Exercise 18

Generator.java
public interface Generator<T>{public T next();}
SmallFish.java
package com.ciaoshen.thinkinjava.chapter15;

public class SmallFish{
    private static long counter=1;
    private final long id=counter++;
    private SmallFish(){}
    public String toString(){return "Small Fish No."+id;}
    public static Generator<SmallFish> generator(){
        return new Generator<SmallFish>(){
            public SmallFish next(){
                return new SmallFish();
            }
        };
    }
}
BigFish.java
package com.ciaoshen.thinkinjava.chapter15;

public class BigFish{
    private static long counter=1;
    private final long id=counter++;
    private BigFish(){}
    public String toString(){return "Big Fish No."+id;}
    public static Generator<BigFish> generator(){
        return new Generator<BigFish>(){
            public BigFish next(){
                return new BigFish();
            }
        };
    }
}
Exercise18.java
package com.ciaoshen.thinkinjava.chapter15;
import java.util.*;
import java.lang.reflect.*;

public class Exercise18{
    public static void eat(BigFish bf, SmallFish sf){
        System.out.println(bf+" EAT "+sf);
    }

    public static void main(String[] args){
        Random rand=new Random();
        Queue<SmallFish> foods=new LinkedList<SmallFish>();
        for(int i=0;i<15;i++){
            foods.add(SmallFish.generator().next());
        }
        List<BigFish> killers=new ArrayList<BigFish>();
        for(int i=0;i<4;i++){
            killers.add(BigFish.generator().next());
        }
        for(SmallFish sf:foods){
            Exercise18.eat(killers.get(rand.nextInt(killers.size())),sf);
        }
    }
}

Exercise 19

Generator.java
interface Generator<T>{public T next();}
Generators.java
public class Generators{
    public static <T> void fill(List<T> list, Generator<T> gen, int num){
        for(int i=0;i<num;i++){
            list.add(gen.next());
        }
    }
}
Product.java
package com.ciaoshen.thinkinjava.chapter15;
import java.util.*;

public class Product {
    private static long count=0;
    private final long id=++count;
    private double price;

    public Product(double price){
        this.price = price;
    }
    public String toString() {
        return "        Product No."+id + " >>> " + "price: $" + price;
    }
    public static Generator<Product> generator = new Generator<Product>() {
        private Random rand = new Random();
        public Product next() {
            return new Product( Math.round(rand.nextDouble() * 1000.0) + 0.99);
        }
    };
}
Container.java
package com.ciaoshen.thinkinjava.chapter15;
import java.util.*;

public class Container extends ArrayList<Product>{
    private static final long serialVersionUID=0;
    private static final int MAX_SIZE=1000;
    private static long count=0;
    private final long id=++count;
    private final int size;

    public Container(int max){
        super();
        size=max;
    }
    public void fill(int numP){
        Generators.fill(this,Product.generator,Math.min(size,numP));
    }
    public String toString(){
        StringBuilder s=new StringBuilder();
        s.append("    Container No."+id+"[Max Size: "+size+"] >>> \n");
        for(Product p:this){
            s.append(p+"\n");
        }
        return s.toString();
    }

    public static Generator<Container> generator = new Generator<Container>(){
        Random rand=new Random();
        public Container next(){
            return new Container(rand.nextInt(MAX_SIZE));
        }
    };
}
Deck.java
package com.ciaoshen.thinkinjava.chapter15;
import java.util.*;

public class Deck extends ArrayList<Container>{
    private static final long serialVersionUID=0;
    private static final int MAX_SIZE=10000;
    private static long count=0;
    private final long id=++count;
    private final int size;
    private Deck(int max){
        super();
        size=max;
    }
    public void fill(int numC, int numP){
        Generators.fill(this, Container.generator, Math.min(size,numC));
        for(Container c:this){
            c.fill(numP);
        }
    }
    public String toString(){
        StringBuilder s=new StringBuilder();
        s.append("Deck No."+id+"[Max Size: "+size+"] >>> \n");
        for(Container c:this){
            s.append(c+"\n");
        }
        return s.toString();
    }
    public static Generator<Deck> generator=new Generator<Deck>(){
        Random rand=new Random();
        public Deck next(){
            return new Deck(rand.nextInt(MAX_SIZE));
        }
    };
}
CargoShip.java
package com.ciaoshen.thinkinjava.chapter15;
import java.util.*;

public class CargoShip extends ArrayList<Deck> {
    private static final long serialVersionUID=0;
    private static final int MAX_SIZE=20;

    public CargoShip(int numD, int numC, int numP) {
        Generators.fill(this,Deck.generator,Math.min(numD,MAX_SIZE));
        for(Deck d:this){
            d.fill(numC,numP);
        }
    }

    public String toString() {
        StringBuilder result = new StringBuilder();
        for(Deck d : this){
            result.append(d+"\n");
        }
        return result.toString();
    }
    public static void main(String[] args) {
        System.out.println(new CargoShip(5,5,5));
    }
}
Exercise19.java
package com.ciaoshen.thinkinjava.chapter15;

public class Exercise19{
    public static void main(String[] args){
        System.out.println(new CargoShip(2,2,2));
    }
}

Exercise 20

I.java
package com.ciaoshen.thinkinjava.chapter15;

public interface I{
    public void a();
    public void b();
}
Impl.java
package com.ciaoshen.thinkinjava.chapter15;

public class Impl implements I{
    public void a(){System.out.println("I am a()!");}
    public void b(){System.out.println("I am b()!");}
    public void c(){System.out.println("I am c()!");}
}
Exercise20.java
package com.ciaoshen.thinkinjava.chapter15;

public class Exercise20{
    public static <T extends I> void generic(T t){
        t.a();
        t.b();
    }
    public static void main(String[] args){
        Exercise20.generic(new Impl());
    }
}

Exercise 21

这题需要注意的是:Map<String,Class<?» typeMap=new HashMap<String,Class<?»(); 这样带通配符的赋值方法竟然可以。也就是Map里可以存不同泛型的Class对象。证明JAVA的泛型是编译时泛型,运行时擦除。

Building.java
package com.ciaoshen.thinkinjava.chapter15;

public class Building {public Building(){System.out.println("I am Building!");}}
House.java
package com.ciaoshen.thinkinjava.chapter15;

public class House extends Building {public House(){System.out.println("I am House!");}}
ClassTypeCapture.java
package com.ciaoshen.thinkinjava.chapter15;
import java.util.*;

public class ClassTypeCapture {
    private Map<String,Class<?>> typeMap=new HashMap<String,Class<?>>();
    public void addType(String key, Class<?> value){
        typeMap.put(key,value);
    }
    public Object createNew(String name){
        Class<?> c=typeMap.get(name);
        try{
            Object o=c.newInstance();
            return o;
        }catch(Exception e){
            System.out.println(e);
            return null;
        }
    }
}
Exercise21.java
package com.ciaoshen.thinkinjava.chapter15;

public class Exercise21{
    public static void main(String[] args){
        ClassTypeCapture ctc=new ClassTypeCapture();
        ctc.addType("Building",Building.class);
        ctc.addType("House",House.class);
        ctc.createNew("Building");
    }
}

Exercise 22

Fruit.java
package com.ciaoshen.thinkinjava.chapter15;

public interface Fruit{public String toString();}
Apple.java
package com.ciaoshen.thinkinjava.chapter15;

public class Apple implements Fruit{
    private String color;
    public Apple(String color){this.color=color;}
    public String toString(){return "A "+color+" Apple!";}
}
Banana.java
package com.ciaoshen.thinkinjava.chapter15;

public class Banana implements Fruit{
    private String color;
    public Banana(String color){this.color=color;}
    public String toString(){return "A "+color+" Banana!";}
}
Factory.java
package com.ciaoshen.thinkinjava.chapter15;

public interface Factory<T>{
    T create();
}
FacApple.java
package com.ciaoshen.thinkinjava.chapter15;
import java.util.*;

public class FacApple implements Factory<Apple>{
    public Apple create(){
        Random rand=new Random();
        int i=rand.nextInt(3);
        String c=new String();
        switch(i){
            case 0:
                c="Red";
                break;
            case 1:
                c="Green";
                break;
            case 2:
                c="Yellow";
                break;

        }
        return new Apple(c);
    }
}
FacBanana.java
package com.ciaoshen.thinkinjava.chapter15;
import java.util.*;

public class FacBanana {
    public static class Fac implements Factory<Banana>{
        public Banana create(){
            Random rand=new Random();
            int i=rand.nextInt(2);
            String c=new String();
            switch(i){
                case 0:
                    c="Green";
                    break;
                case 1:
                    c="Yellow";
                    break;

            }
            return new Banana(c);
        }
    }
}
Plate.java
package com.ciaoshen.thinkinjava.chapter15;
import java.util.*;

public class Plate<T>{
    private List<T> list=new ArrayList<T>();
    public <F extends Factory<T>> Plate(F f){
        list.add(f.create());
    }
    public void add(Factory<T> f){list.add(f.create());}
    public T get(int index){return (index<list.size())? list.get(index):null;}
}
Exercise22.java
package com.ciaoshen.thinkinjava.chapter15;
import java.util.*;

public class Exercise22{
    public static void main(String[] args){
        //测试苹果盘子
        FacApple fa=new FacApple();
        Plate<Apple> pa=new Plate<Apple>(fa);
        pa.add(fa);
        System.out.println(pa.get(0));
        System.out.println(pa.get(1));
        //测试香蕉盘子
        FacBanana.Fac fb=new FacBanana.Fac();
        Plate<Banana> pb=new Plate<Banana>(fb);
        pb.add(fb);
        System.out.println(pb.get(0));
        System.out.println(pb.get(1));
    }
}

Exercise 23

FactoryI.java
package com.ciaoshen.thinkinjava.chapter15;
import java.util.*;

public interface FactoryI<T> {
    List<T> create(int num);
}
IntegerFactory.java
package com.ciaoshen.thinkinjava.chapter15;
import java.util.*;

public class IntegerFactory implements FactoryI<Integer> {
    public List<Integer> create(int num) {
        List<Integer> list=new ArrayList<Integer>();
        for(int i=0;i<num;i++){
            list.add(i);
        }
        return list;
    }
}
Foo2.java
package com.ciaoshen.thinkinjava.chapter15;
import java.util.*;

public class Foo2<T> {
    private List<T> x;
    public <F extends FactoryI<T>> Foo2(F factory, int num) {
        x = factory.create(num);
    }
}
Widget.java
package com.ciaoshen.thinkinjava.chapter15;
import java.util.*;

public class Widget {
    public static class Factory implements FactoryI<Widget> {
        public List<Widget> create(int num) {
            List<Widget> list=new ArrayList<Widget>();
            for(int i=0;i<num;i++){
                list.add(new Widget());
            }
            return list;
        }
    }
}
Exercise23.java
package com.ciaoshen.thinkinjava.chapter15;
import java.util.*;

public class Exercise23{
    public static void main(String[] args) {
        new Foo2<Integer>(new IntegerFactory(),10);
        new Foo2<Widget>(new Widget.Factory(),10);
    }
}

Exercise 24

Factory.java
package com.ciaoshen.thinkinjava.chapter15;

public interface Factory<T>{
    T create();
}
Building.java
package com.ciaoshen.thinkinjava.chapter15;

public class Building {public Building(){System.out.println("I am Building!");}}
House.java
package com.ciaoshen.thinkinjava.chapter15;

public class House extends Building {public House(){System.out.println("I am House!");}}
FacBuilding.java
package com.ciaoshen.thinkinjava.chapter15;

public class FacBuilding implements Factory<Building>{
    public Building create(){return new Building();}
}
FacHouse.java
package com.ciaoshen.thinkinjava.chapter15;

public class FacBuilding implements Factory<Building>{
    public Building create(){return new Building();}
}
Exercise24.java
package com.ciaoshen.thinkinjava.chapter15;
import java.util.*;

public class Exercise24 {
    private Map<String,Factory<?>> typeMap=new HashMap<String,Factory<?>>();

    public void addType(String key, Factory<?> value){
        typeMap.put(key,value);
    }
    public Object createNew(String name){
        Factory<?> f=typeMap.get(name);
        try{
            Object o=f.create();
            return o;
        }catch(Exception e){
            System.out.println(e);
            return null;
        }
    }
    public static void main(String[] args) {
        Exercise24 ctc=new Exercise24();
        ctc.addType("Building",new FacBuilding());
        ctc.addType("House",new FacHouse());
        ctc.createNew("Hello");   //Exception: java.lang.NullPointerException
        ctc.createNew("Building");
        ctc.createNew("House");
    }
}

Exercise 25

Interface1.java
package com.ciaoshen.thinkinjava.chapter15;

public interface Interface1{public void print1();}
Interface2.java
package com.ciaoshen.thinkinjava.chapter15;

public interface Interface2{public void print2();}
Implementation.java
package com.ciaoshen.thinkinjava.chapter15;

public class Implementation implements Interface1, Interface2{
    public void print1(){System.out.println("Inherit from Interface1!");}
    public void print2(){System.out.println("Inherit from Interface2!");}
}
Exercise25.java
package com.ciaoshen.thinkinjava.chapter15;

public class Exercise25{
    public static <T extends Interface1> void foo1(T t){t.print1();}
    public static <V extends Interface2> void foo2(V v){v.print2();}
    public static void main(String[] args){
        Exercise25.foo1(new Implementation());
        Exercise25.foo2(new Implementation());
    }
}

Exercise 26

public class Exercise26{
    public static void main(String[] args){
        Number[] numArray=new Integer[10];
        for(int i=0;i<10;i++){
            numArray[i]=new Integer(i);
        }
        for(int i=0;i<10;i++){
            System.out.println(numArray[i]);
        }
    }
}

Exercise 27

package com.ciaoshen.thinkinjava.chapter15;
import java.util.*;

public class Exercise27{
    public static void main(String[] args){
        //List<Number> numList1=new ArrayList<Integer>();  //Error
        List<? extends Number> numList2=new ArrayList<Integer>();
    }
}

Exercise 28

Generic1.java
package com.ciaoshen.thinkinjava.chapter15;

public class Generic1<T>{
    private T item;
    public Generic1(T t){item=t;}
    public void set(T t){item=t;}
    public String toString(){return String.valueOf(item);}
}
Generic2.java
package com.ciaoshen.thinkinjava.chapter15;

public class Generic2<T>{
    private T item;
    public Generic2(T t){item=t;}
    public T get(){return item;}
}
Exercise28.java
public class Exercise28{

    public static <T> void foo1(Generic1<? super T> g, T t){g.set(t);}
    public static <V> V foo2(Generic2<? extends V> g){return g.get();}

    public static void main(String[] args){
        Generic1<Number> genNum=new Generic1<Number>(new Integer(0));
        Generic2<Integer> genInt=new Generic2<Integer>(new Integer(222));
        Exercise28.foo1(genNum, new Float(111.1f));
        System.out.println(genNum);
        Integer i=Exercise28.foo2(genInt);
        System.out.println(i);
    }
}

Exercise 29

Holder.java
package com.ciaoshen.thinkinjava.chapter15;

public class Holder<T> {
    private T obj;
    public Holder(T t){obj=t;}
    public void set(T obj) { this.obj = obj; }
    public T get() { return obj; }
    public String toString(){return obj.toString();}
}
Exercise29.java
package com.ciaoshen.thinkinjava.chapter15;
import java.util.*;

public class Exercise29{
    public static void setList(List<?> l){
        System.out.println(l.getClass().getSimpleName());
        System.out.println(l.get(1));
    }
    public static void holderSet(Holder<? extends List<?>> h){
        //h.set(new ArrayList<String>(Arrays.asList("Hello World".split(" "))));    //Error: mismatch; ArrayList<String> cannot be converted to CAP#1
    }
    public static List<?> holderGet(Holder<? extends List<?>> h){
        return h.get();
    }
    public static void listSet(Holder<? extends List<?>> h){
        List<?> list=h.get();
        //list.add("TOTO");     //Error: mismatch; ArrayList<String> cannot be converted to CAP#1
    }
    public static Object listGet(Holder<? extends List<?>> h){
        List<?> list=h.get();
        return list.get(1);
    }

    public static void main(String[] args){
        List<Integer> li=new ArrayList<Integer>();
        li.addAll(Arrays.asList(1,2,3,4,5,6,7,8,9,10));
        Holder<List<Integer>> hli=new Holder<List<Integer>>(li);
        System.out.println(hli);
        Exercise29.setList(li);
        //Exercise29.holderSet(hli);    //Error: argument mismatch; ArrayList<String> cannot be converted to CAP#1
        System.out.println(Exercise29.holderGet(hli));
        //Exercise29.listSet(hli);    //Error: argument mismatch; String cannot be converted to CAP#1
        System.out.println(Exercise29.listGet(hli));
    }
}

Exercise 30

Holder.java
package com.ciaoshen.thinkinjava.chapter15;

public class Holder<T> {
    private T obj;
    public Holder(T t){obj=t;}
    public void set(T obj) { this.obj = obj; }
    public T get() { return obj; }
    public String toString(){return obj.toString();}
}
IntegerHolder.java
package com.ciaoshen.thinkinjava.chapter15;

public class IntegerHolder extends Holder<Integer>{
    public IntegerHolder(Integer i){super(i);}
}
Exercise30.java
package com.ciaoshen.thinkinjava.chapter15;

public class Exercise30{
    public static void main(String[] args){
        for(int i=0;i<10;i++){
            IntegerHolder ih=new IntegerHolder(i);
        }
    }
}

Exercise 31

Payable.java
package com.ciaoshen.thinkinjava.chapter15;

public interface Payable {}
Employee.java
package com.ciaoshen.thinkinjava.chapter15;

public class Employee implements Payable {}
Hourly.java
package com.ciaoshen.thinkinjava.chapter15;

class Hourly extends Employee {}
Exercise31.java
package com.ciaoshen.thinkinjava.chapter15;

public class Exercise31{
    public static void main(String[] args){
        Employee e=new Employee();
        Hourly h=new Hourly();
    }
}

Exercise 32

FixedSizeStack.java
package com.ciaoshen.thinkinjava.chapter15;

public class FixedSizeStack<T> {
    private int index = 0;
    private Object[] storage;
    public FixedSizeStack(int size) {
        storage = new Object[size];
    }
    public void push(T item) { storage[index++] = item; }
    @SuppressWarnings("unchecked")
    public T pop() { return (T)storage[--index]; }
}
Exercise32.java
package com.ciaoshen.thinkinjava.chapter15;

public class Exercise32 {
    public static final int SIZE = 10;
    public static void main(String[] args) {
        FixedSizeStack<String> strings = new FixedSizeStack<String>(SIZE);
        for(String s : "A B C D E F G H I J".split(" ")){
            strings.push(s);
        }
        //strings.push("end");    //Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException
        for(int i = 0; i < SIZE; i++) {
            String s = strings.pop();
            System.out.print(s + " ");
        }
    }
}

Exercise 33

ArrayFixedSizeStack.java
package com.ciaoshen.thinkinjava.chapter15;
import java.util.*;

public class ArrayFixedSizeStack<T> {
    private int index = 0;
    private List<Object> storage;
    public ArrayFixedSizeStack() {
        storage = new ArrayList<Object>();
    }
    public void push(T item) { storage.add(item); index++; }
    @SuppressWarnings("unchecked")
    public T pop() { return (T)storage.get(--index); }
    public boolean hasNext(){return index>0;}
}
Exercise33.java
package com.ciaoshen.thinkinjava.chapter15;
import java.util.*;

public class Exercise33 {
    public static void main(String[] args) {
        ArrayFixedSizeStack<String> strings = new ArrayFixedSizeStack<String>();
        for(String s : "A B C D E F G H I J".split(" ")){
            strings.push(s);
        }
        strings.push("end");    //Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException
        while(strings.hasNext()) {
            String s = strings.pop();
            System.out.print(s + " ");
        }
    }
}

Exercise 34

自限定类对于需要互相比较的对象比较合适。相当于限定了圆形只能和圆形比较面积,长方形只能和长方形比较面积。

Shape.java
package com.ciaoshen.thinkinjava.chapter15;
import java.lang.Math.*;

public abstract class Shape<T extends Shape<T>>{
    public boolean isLarger(T t){return this.area()>t.area();}
    public boolean isSmaller(T t){return this.area()<t.area();}
    public boolean equal(T t){return this.area()==t.area();}
    public abstract double area();
}
Circle.java
package com.ciaoshen.thinkinjava.chapter15;
import java.lang.Math.*;

public class Circle extends Shape<Circle>{
    private double radius;
    public Circle(double r){radius=r;}
    public double area(){
        return Math.PI*radius*radius;
    }
}
Rectangle.java
package com.ciaoshen.thinkinjava.chapter15;
import java.lang.Math.*;

public class Rectangle extends Shape<Rectangle>{
    private double width;
    private double height;
    public Rectangle(double w, double h){width=w; height=h;}
    public double area(){
        return width*height;
    }
}
Exercise34.java
package com.ciaoshen.thinkinjava.chapter15;
import java.lang.Math.*;

public class Exercise34 {
    public static void main(String[] args) {
        //自限定的意义在于:圆形只能和圆形比较面积
        Circle c1=new Circle(11.1);
        Circle c2=new Circle(15.5);
        System.out.println(c1.isLarger(c2));
        System.out.println(c1.isSmaller(c2));
        System.out.println(c1.equal(c2));
        //自限定的意义在于:长方形只能和长方形比较面积
        Rectangle r1=new Rectangle(4.0,6.0);
        Rectangle r2=new Rectangle(3.0,8.0);
        System.out.println(r1.isLarger(r2));
        System.out.println(r1.isSmaller(r2));
        System.out.println(r1.equal(r2));
        //不允许比较长方形和圆形的面积
        System.out.println(r1.isLarger(c2));
        System.out.println(r1.isSmaller(c2));
        System.out.println(r1.equal(c2));
    }
}

Exercise 35

Coffee.java
package com.ciaoshen.thinkinjava.chapter15;

public class Coffee{
    private static long count;
    private long id;
    public Coffee(){id=count++;}
    public long showId(){return id;}
}
Latte.java
package com.ciaoshen.thinkinjava.chapter15;

public class Latte extends Coffee{
    public String toString(){return "No."+String.valueOf(showId())+">>> I am Latte!";}
}
Capuccino.java
package com.ciaoshen.thinkinjava.chapter15;

public class Capuccino extends Coffee{
    public String toString(){return "No."+String.valueOf(showId())+">>> I am Capuccino!";}
}
Esppresso.java
package com.ciaoshen.thinkinjava.chapter15;

public class Esppresso extends Coffee{
    public String toString(){return "No."+String.valueOf(showId())+">>> I am Esppresso!";}
}
Exercise35.java
package com.ciaoshen.thinkinjava.chapter15;
import java.util.*;

public class Exercise35{
    @SuppressWarnings({"rawtypes","unchecked"})
    static void oldStyleMethod(List probablyCapuccino) {
        probablyCapuccino.add(new Latte());
    }

    @SuppressWarnings({"rawtypes","unchecked"})
    public static void main(String[] args){
        //unsafe list
        List<Capuccino> capUnsafe=new ArrayList<Capuccino>();
        Exercise35.oldStyleMethod(capUnsafe); //ClassCastException
        //safe list
        try{
            List<Capuccino> capSafe=Collections.checkedList(new ArrayList<Capuccino>(), Capuccino.class);
            Exercise35.oldStyleMethod(capSafe);
        }catch(Exception e){
            System.out.println(e);
        }
    }
}

Exercise 36

Processor.java
package com.ciaoshen.thinkinjava.chapter15;
import java.util.*;

public interface Processor<T,E extends Exception, F extends Exception> {
    public void process(List<T> resultCollector) throws E,F;
}
ProcessorRunner.java
package com.ciaoshen.thinkinjava.chapter15;
import java.util.*;

public class ProcessRunner<T,E extends Exception, F extends Exception> extends ArrayList<Processor<T,E,F>> {
    private static final long serialVersionUID=0;
    public List<T> processAll() throws E,F {
        List<T> resultCollector = new ArrayList<T>();
        for(Processor<T,E,F> processor : this){
            processor.process(resultCollector);
        }
        return resultCollector;
    }
}
Failure1.java
package com.ciaoshen.thinkinjava.chapter15;

public class Failure1 extends Exception {private static final long serialVersionUID=0;}
Failure2.java
package com.ciaoshen.thinkinjava.chapter15;
import java.util.*;

public class Failure3 extends Exception {private static final long serialVersionUID=0;}
Processor1.java
package com.ciaoshen.thinkinjava.chapter15;
import java.util.*;

public class Processor1 implements Processor<String,Failure1,Failure3> {
    private static int count = 3;
    public void process(List<String> resultCollector) throws Failure1,Failure3 {
        if(count>=5){
            throw new Failure3();
        }
        if(count-- > 1){
            resultCollector.add("Hep!");
        }else{
            resultCollector.add("Ho!");
        }
        if(count<-1){
            throw new Failure1();
        }
    }
}
Processor2.java
package com.ciaoshen.thinkinjava.chapter15;
import java.util.*;

public class Processor2 implements Processor<Integer,Failure2,Failure3> {
    private static int count = 5;
    public void process(List<Integer> resultCollector) throws Failure2,Failure3 {
        if(count>=5){
            throw new Failure3();
        }
        if(count-- == 0){
            resultCollector.add(47);
        } else {
            resultCollector.add(11);
        }
        if(count<-1){
            throw new Failure3();
        }
    }
}
Exercise36.java
package com.ciaoshen.thinkinjava.chapter15;
import java.util.*;

public class Exercise36{
    public static void main(String[] args){
        ProcessRunner<String,Failure1,Failure3> runner = new ProcessRunner<String,Failure1,Failure3>();
        for(int i = 0; i < 3; i++){
            runner.add(new Processor1());
        }
        try {
            System.out.println(runner.processAll());
        } catch(Failure1 e1) {
            System.out.println(e1);
        } catch(Failure3 e3){
            System.out.println(e3);
        }

        ProcessRunner<Integer,Failure2,Failure3> runner2 = new ProcessRunner<Integer,Failure2,Failure3>();
        for(int i = 0; i < 5; i++){
            runner2.add(new Processor2());
        }
        try {
            System.out.println(runner2.processAll());
        } catch(Failure2 e2) {
            System.out.println(e2);
        } catch(Failure3 e3){
            System.out.println(e3);
        }
    }
}

Exercise 37

/**
 *  时间戳系统
 */
interface TimeStamped { long getStamp(); }

class TimeStampedImp implements TimeStamped {
    private final long timeStamp;
    public TimeStampedImp() {
        timeStamp = new Date().getTime();
    }
    public long getStamp() { return timeStamp; }
}

/**
 *  序列号系统
 */
interface SerialNumbered { long getSerialNumber(); }

class SerialNumberedImp implements SerialNumbered {
    private static long counter = 1;
    private final long serialNumber = counter++;
    public long getSerialNumber() { return serialNumber; }
}

/**
 *  版本系统(附加的第三个混型)
 */
interface VersionId { public double getVersionId();}

class VersionIdImp implements VersionId {
    private double version=1.0;
    public VersionIdImp(double v){version=v;}
    public void progressVersion(){version+=0.1;}
    public double getVersionId(){return version;}
}

/**
 *  白板类系统
 */
interface Basic {
    public void set(String val);
    public String get();
}
class BasicImp implements Basic {
    private String value;
    public void set(String val) { value = val; }
    public String get() { return value; }
}

/**
 *  混型系统
 */
class Mixin extends BasicImp implements TimeStamped, SerialNumbered {
    private TimeStamped timeStamp = new TimeStampedImp();
    private SerialNumbered serialNumber = new SerialNumberedImp();
    private VersionId id=new VersionIdImp(1.0);
    public long getStamp() { return timeStamp.getStamp(); }
    public long getSerialNumber() { return serialNumber.getSerialNumber(); }
    public double getVersionId(){ return id.getVersionId();}
}

/**
 *  测试
 */
public class Exercise37 {
    public static void main(String[] args) {
        Mixin mixin1 = new Mixin(), mixin2 = new Mixin();
        mixin1.set("test string 1");
        mixin2.set("test string 2");
        System.out.println(mixin1.get() + " " + mixin1.getStamp() + " " + mixin1.getSerialNumber()+ " " + mixin1.getVersionId());
        System.out.println(mixin2.get() + " " + mixin2.getStamp() + " " + mixin2.getSerialNumber()+ " " + mixin2.getVersionId());
    }
}

Exercise 38

class Coffee{
    private int volumn;
    public Coffee(int v){volumn=v;}
    public void drink(int v){volumn= (v<=volumn)? volumn-v:0;}
    public int checkRest(){return volumn;}
}
class Decorator extends Coffee{
    Coffee c;
    public Decorator(Coffee c, int ex){
        super(c.checkRest()+ex);
        this.c=c;
    }
}
class MilkCoffee extends Decorator{
    public MilkCoffee(Coffee c,int ex){
        super(c,ex);
    }
}
class FoamCoffee extends Decorator{
    public FoamCoffee(Coffee c,int ex){
        super(c,ex);
    }
}
class CaramelCoffee extends Decorator{
    public CaramelCoffee(Coffee c,int ex){
        super(c,ex);
    }
}
class ChocolateCoffee extends Decorator{
    public ChocolateCoffee(Coffee c,int ex){
        super(c,ex);
    }
}
public class Exercise38 {
    public static void main(String[] args) {
        //制作玛奇朵
        MilkCoffee latte=new MilkCoffee(new Coffee(10),10);
        FoamCoffee cappuccino=new FoamCoffee(latte,5);
        cappuccino.drink(7);    //服务员偷喝一口
        CaramelCoffee macchiato=new CaramelCoffee(cappuccino,3);

        System.out.println(macchiato.checkRest());
        macchiato.drink(10);
        System.out.println(macchiato.checkRest());

    }
}

Exercise 39

/**
 *  tuple容器
 */
class TwoTuple<A,B> {
    public final A first;
    public final B second;
    public TwoTuple(A a, B b) { first = a; second = b; }
    public String toString() {
        return "(" + first + ", " + second + ")";
    }
    public static <A,B> TwoTuple<A,B> tuple(A a, B b) {
        return new TwoTuple<A,B>(a, b);
    }
}
/**
 *  时间戳系统
 */
interface TimeStamped { long getStamp(); }

class TimeStampedImp implements TimeStamped {
    private final long timeStamp;
    public TimeStampedImp() {
        timeStamp = new Date().getTime();
    }
    public long getStamp() { return timeStamp; }
}
/**
 *  序列号系统
 */
interface SerialNumbered { long getSerialNumber(); }

class SerialNumberedImp implements SerialNumbered {
    private static long counter = 1;
    private final long serialNumber = counter++;
    public long getSerialNumber() { return serialNumber; }
}
/**
 *  新加的Colored系统
 */
interface Colored {public boolean isColored();}

class ColoredImp implements Colored {
    private boolean colored;
    public ColoredImp(boolean c){colored=c;}
    public void makeColor(){colored=true;}
    public void removeColor(){colored=false;}
    public boolean isColored(){return colored;}
}
/**
 *  动态代理
 */
class MixinProxy implements InvocationHandler {
    Map<String,Object> delegatesByMethod;
    public MixinProxy(TwoTuple<Object,Class<?>>... pairs) {
        delegatesByMethod = new HashMap<String,Object>();
        for(TwoTuple<Object,Class<?>> pair : pairs) {
            for(Method method : pair.second.getMethods()) {
                String methodName = method.getName();
                // The first interface in the map
                // implements the method.
                if (!delegatesByMethod.containsKey(methodName))
                    delegatesByMethod.put(methodName, pair.first);
            }
        }
    }
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String methodName = method.getName();
        Object delegate = delegatesByMethod.get(methodName);
        return method.invoke(delegate, args);
    }

    @SuppressWarnings("unchecked")
    public static Object newInstance(TwoTuple... pairs) {
        Class[] interfaces = new Class[pairs.length];
        for(int i = 0; i < pairs.length; i++) {
            interfaces[i] = (Class)pairs[i].second;
        }
        ClassLoader cl = pairs[0].first.getClass().getClassLoader();
        return Proxy.newProxyInstance(cl, interfaces, new MixinProxy(pairs));
    }
}
/**
 *  测试
 */
public class Exercise39 {
    public static void main(String[] args) {
        Object mixin = MixinProxy.newInstance(TwoTuple.tuple(new BasicImp(), Basic.class),
                                              TwoTuple.tuple(new TimeStampedImp(), TimeStamped.class),
                                              TwoTuple.tuple(new SerialNumberedImp(),SerialNumbered.class),
                                              TwoTuple.tuple(new ColoredImp(false),Colored.class));
        Basic b = (Basic)mixin;
        TimeStamped t = (TimeStamped)mixin;
        SerialNumbered s = (SerialNumbered)mixin;
        Colored c=(Colored)mixin;
        b.set("Hello");
        System.out.println(b.get());
        System.out.println(t.getStamp());
        System.out.println(s.getSerialNumber());
        System.out.println(c.isColored());
    }
}

Exercise 40

/**
 *  Exercise 40
 */
package com.ciaoshen.thinkinjava.chapter15;
import java.util.*;
import java.lang.reflect.*;
/**
 *  LEV 1
 */
class Individual{
    private String name;
    public Individual(){this.name="NULL";}
    public Individual(String name){this.name=name;}
    public void speak(){System.out.println("...");}
}
/**
 *  LEV 2
 */
class Person extends Individual {
    public Person(String name) { super(name); }
    @Override
    public void speak(){System.out.println("Hello World!");}
}
class Pet extends Individual {
    public Pet(String name) { super(name); }
    public Pet() { super(); }
    @Override
    public void speak(){System.out.println("!!!");}
}
/**
 *  LEV 3 - 狗,猫,鼠
 */
class Dog extends Pet {
    public Dog(String name) { super(name); }
    public Dog() { super(); }
    @Override
    public void speak(){System.out.println("WongWong!!!");}
}
class Cat extends Pet {
    public Cat(String name) { super(name); }
    public Cat() { super(); }
    @Override
    public void speak(){System.out.println("MiewMiew!!!");}
}
class Rodent extends Pet {
    public Rodent(String name) { super(name); }
    public Rodent() { super(); }
    @Override
    public void speak(){System.out.println("JiJiJi!!!");}
}
/**
 *  LEV 4 - 狗系
 */
class Mutt extends Dog {
    public Mutt(String name) { super(name); }
    public Mutt() { super(); }
}
class Pug extends Dog {
    public Pug(String name) { super(name); }
    public Pug() { super(); }
}
/**
 *  LEV 4 - 猫系
 */
class EgyptianMau extends Cat {
    public EgyptianMau(String name) { super(name); }
    public EgyptianMau() { super(); }
}

class Manx extends Cat {
    public Manx(String name) { super(name); }
    public Manx() { super(); }
}
/**
 *  LEV 4 - 鼠系
 */
class Rat extends Rodent {
    public Rat(String name) { super(name); }
    public Rat() { super(); }
}
class Mouse extends Rodent {
    public Mouse(String name) { super(name); }
    public Mouse() { super(); }
}
class Hamster extends Rodent {
    public Hamster(String name) { super(name); }
    public Hamster() { super(); }
}
/**
 *  Apply类
 */
class Apply {
    public static <T, S extends Iterable<? extends T>> void apply(S seq, Method f, Object... args) {
        try {
            for(T t: seq)
                f.invoke(t, args);
        } catch(Exception e) {
            // Failures are programmer errors
            throw new RuntimeException(e);
        }
    }
}
/**
 *  测试类
 */
public class Exercise40{
    public static void main(String[] args){
        List<Pet> lp=new ArrayList<Pet>();
        lp.add(new Mutt("MuMu"));
        lp.add(new Pug("PuPu"));
        lp.add(new EgyptianMau("MauMau"));
        lp.add(new Manx("ManMan"));
        lp.add(new Rat("RaRa"));
        lp.add(new Mouse("MouMou"));
        lp.add(new Hamster("HaHa"));

        try{
            Apply.apply(lp,Pet.class.getMethod("speak"));
        }catch(Exception e){
            System.out.println(e);
        }
    }
}

Exercise 41

//addable接口
interface Addable<T> { void add(T t); }

//面向Addable接口的fill方法
class FillPets {
    //用反射填充容器
    public static <T extends Pet> void fill(Addable<T> addable, Class<? extends T> classToken, int size) {
        for(int i = 0; i < size; i++){
            try {
                addable.add(classToken.newInstance());
            } catch(Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
}
/** 《适配器》
 * 原理是类库里的Collection和SimpleQueue动不了。
 * 那就给他们都套一层代理。然后新的代理类实现Addable接口。
 */
//Collection是通过组合的方式套代理
class AddableCollectionAdapter<T> implements Addable<T> {
    private Collection<T> c;
    public AddableCollectionAdapter(Collection<T> c) {
        this.c = c;
    }
    public void add(T item) { c.add(item); }
}
// 把加了add()方法的容器的引用,赋值给Addable接口。
class Adapter {
    public static <T> Addable<T> collectionAdapter(Collection<T> c) {
        return new AddableCollectionAdapter<T>(c);
    }
}
//SimpleQueue
class SimpleQueue<T> implements Iterable<T> {
    private LinkedList<T> storage = new LinkedList<T>();
    public void add(T t) { storage.offer(t); }
    public T get() { return storage.poll(); }
    public Iterator<T> iterator() {
        return storage.iterator();
    }
}
//SimpleQueue的派生类实现Addable接口。
class AddableSimpleQueue<T> extends SimpleQueue<T> implements Addable<T> {
    public void add(T item) { super.add(item); }
}
/**
 *  LEV 1
 */
class Individual{
    private String name;
    public Individual(){this.name="NULL";}
    public Individual(String name){this.name=name;}
    public void speak(){System.out.println("...");}
}
/**
 *  LEV 2
 */
class Person extends Individual {
    public Person(String name) { super(name); }
    @Override
    public void speak(){System.out.println("Hello World!");}
}

class Pet extends Individual {
    public Pet(String name) { super(name); }
    public Pet() { super(); }
    @Override
    public void speak(){System.out.println("!!!");}
}
/**
 *  LEV 3 - 狗,猫,鼠
 */
class Dog extends Pet {
    public Dog(String name) { super(name); }
    public Dog() { super(); }
    @Override
    public void speak(){System.out.println("WongWong!!!");}
}
class Cat extends Pet {
    public Cat(String name) { super(name); }
    public Cat() { super(); }
    @Override
    public void speak(){System.out.println("MiewMiew!!!");}
}
class Rodent extends Pet {
    public Rodent(String name) { super(name); }
    public Rodent() { super(); }
    @Override
    public void speak(){System.out.println("JiJiJi!!!");}
}
/**
 *  LEV 4 - 狗系
 */
class Mutt extends Dog {
    public Mutt(String name) { super(name); }
    public Mutt() { super(); }
}
class Pug extends Dog {
    public Pug(String name) { super(name); }
    public Pug() { super(); }
}
/**
 *  LEV 4 - 猫系
 */
class EgyptianMau extends Cat {
    public EgyptianMau(String name) { super(name); }
    public EgyptianMau() { super(); }
}
class Manx extends Cat {
    public Manx(String name) { super(name); }
    public Manx() { super(); }
}
/**
 *  LEV 4 - 鼠系
 */
class Rat extends Rodent {
    public Rat(String name) { super(name); }
    public Rat() { super(); }
}
class Mouse extends Rodent {
    public Mouse(String name) { super(name); }
    public Mouse() { super(); }
}
class Hamster extends Rodent {
    public Hamster(String name) { super(name); }
    public Hamster() { super(); }
}
/**
 *  测试类
 */
public class Exercise41{
    public static void main(String[] args){
        //Pet容器
        List<Dog> dogs=new ArrayList<Dog>();
        //给Pet容器套上实现了Addable接口的适配器,就能用面向Addable接口的fill()方法了。
        Fill2.fill(new AddableCollectionAdapter<Dog>(dogs),Mutt.class, 3);
        //用辅助方法获得Addable接口对象实例
        Fill2.fill(Adapter.collectionAdapter(dogs), Pug.class, 2);
        for(Dog d: dogs){
            d.speak();
        }
        System.out.println("----------------------");

        //SimpleQueue实现了Addable()接口与的派生类。也可以用fill()方法填充。
        AddableSimpleQueue<Cat> catQueue = new AddableSimpleQueue<Cat>();
        Fill2.fill(catQueue, EgyptianMau.class, 4);
        Fill2.fill(catQueue, Manx.class, 1);
        for(Cat c: catQueue){
            c.speak();
        }
    }
}

Exercise 42

/**
 *  统一接口:黑箱子
 */
interface BlackBox<T>{
    public void set(T t);
    public T function();
}
/**
 *  两个独立的类
 */
//魔数=31的简单散列值
class Hasher implements BlackBox<Long>{
    private Long num=0l;
    public void set(Long n){num=n;}
    public Long function(){return 31*num;}
}
//返回5范围内的上下浮动值
class Floater implements BlackBox<Integer>{
    private Integer num=0;
    private Random rand=new Random();
    public void set(Integer n){n=num;}
    public Integer function(){return (rand.nextInt(2)==0)? num+rand.nextInt(5):num-rand.nextInt(5);}
}
/**
 *  Functional
 */
class NewFunctional{
    public static <T> List<T> doSomething(Collection<T> c, BlackBox<T> bb){
        List<T> result=new ArrayList<T>();
        for(T t:c){
            bb.set(t);
            result.add(bb.function());
        }
        return result;
    }
}
/**
 *  测试
 */
public class Exercise42 {
    public static void main(String[] args) {
        List<Long> ll=new ArrayList<Long>();
        ll.addAll(Arrays.asList(11111l,22222l,33333l,44444l,55555l));

        List<Integer> li=new ArrayList<Integer>();
        li.addAll(Arrays.asList(111,222,333,444,555));

        List<Long> result1=NewFunctional.doSomething(ll,new Hasher());
        System.out.println(result1);

        List<Integer> result2=NewFunctional.doSomething(li,new Floater());
        System.out.println(result2);
    }
}