1. 程式人生 > >Java-Java程式設計思想第四版 第十五章 練習

Java-Java程式設計思想第四版 第十五章 練習

練習1:

// Use Holder3 with the typeinfo.pets library to show that a Holder3 that is
// specified to hold a base type can also hold a derived type.

import typeinfo.pets.*;
class Holder<T>{
    private T a;
    Holder(T a){this.a=a;}
    void f(){System.out.println(a);}
    void set(T a){this.a=a;}
}
public class Ja15_1{
    public static void main(String[] args){
        Holder<Pet> h=new Holder<Pet>(new Pet("fsdf"));
        h.f();
        h.set(new Dog("dogg"));
        h.f();
        h.set(new Cat("catt"));
        h.f();
        
    }

}
// Use Holder3 with the typeinfo.pets library to show that a Holder3 that is
// specified to hold a base type can also hold a derived type.

import typeinfo.pets.*;
class Holder<T>{
    private T a;
    Holder(T a){this.a=a;}
    void f(){System.out.println(a);}
    void set(T a){this.a=a;}
}
public class Ja15_1{
    public static void main(String[] args){
        Holder<Pet> h=new Holder<Pet>(new Pet("fsdf"));
        h.f();
        h.set(new Dog("dogg"));
        h.f();
        h.set(new Cat("catt"));
        h.f();
        
    }

}

練習2:

/* Create a holder class that holds three objects of the same type along 
* with the methods to store and fetch those objects and a constructor to 
* initialize all three.
*/ 
import static net.mindview.util.Print.*;
import typeinfo.pets.*;
public class Ja15_2<T>{
    private T a;
    private T b;
    private T c;
    Ja15_2(){a=null;b=null;c=null;}
    void setA(T a){this.a=a;}
    void setB(T b){this.b=b;}
    void setC(T c){this.c=c;}
      void getA(){print( a);}
    void getB(){print( b);}
    void getC(){print( c);}
    public static void main(String[] args){
        Ja15_2<Pet> ja=new Ja15_2<Pet>();
        ja.setA(new Cat("cat"));
        ja.setB(new Dog("dog"));
        ja.setC(new Pug("pug"));
        ja.getA();
        ja.getB();
        ja.getC();
    }
} 

練習3:

// Create and test a SixTuple generic.
import net.mindview.util.*;
import typeinfo.pets.*;
import static net.mindview.util.Print.*;

public class Ja15_3<A,B,C,D,E,F> extends FiveTuple<A,B,C,D,E>{
    public final F sixth;
    Ja15_3(A a, B b, C c, D d, E e,F f){
        super(a,b,c,d,e);
        sixth=f;
    }
    public String toString(){return "(" + first + ", " + second + ", " +third + ", " + fourth + ", " + fifth +", " +sixth+")";}
    public static void main(String[] args){
          Ja15_3<Cat,Dog,Pug,Pet,String,Integer> ja=new Ja15_3<Cat,Dog,Pug,Pet,String,Integer>(new Cat(),new Dog(),new Pug(),new Pet(),"das",56);
          print(ja);
          
    }    
}

練習4:

// 'Generify' innerclasses/Ja15_4.java.
interface Selector<TT> {
  boolean end();
  TT current();
  void next();
}	

public class Ja15_4<TT> {
  private TT[] items;
  private int next = 0;
  public Ja15_4(TT[] mm) { items = mm; }
  public void add(TT x) {
    if(next < items.length)
      items[next++] = x;
  }
  private class Ja15_4Selector implements Selector<TT> {
    private int i = 0;
    public boolean end() { return i == items.length; }
    public TT current() { return items[i]; }
    public void next() { if(i < items.length) i++; }
  }
  public Selector selector() {
    return new Ja15_4Selector();
  }	
  public static void main(String[] args) {
    Ja15_4<String> sequence = new Ja15_4<String>(new String[10]);
    for(int i = 0; i < 10; i++)
      sequence.add(Integer.toString(i));
    Selector selector = sequence.selector();
    while(!selector.end()) {
      System.out.print(selector.current() + " ");
      selector.next();
    }
  }
}


練習5:

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


練習6:

// Use RandomList with two more types in addition to the one shown in main().

import java.util.*;

public class Ja15_6<T> {
  private ArrayList<T> storage = new ArrayList<T>();
  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) {
    Ja15_6<Integer> rs = new Ja15_6<Integer>();
    for(Integer s: Arrays.asList(4,6,87,211,76))//形成陣列方法
      rs.add(s);
    for(int i = 0; i < 11; i++)
      System.out.print(rs.select() + " ");
  }
}


練習7:

// Use composition instead of inheritance to adapt Fibonacci
// to make it interable.
import java.util.*;
import net.mindview.util.*;
import generics.*;

public class Ja15_7 implements Generator<Integer>,Iterable<Integer> {
    private int count = 0;
    public Integer next() { return fib(count++); }
    private int fib(int n) {
        if(n < 2) return 1;
        return fib(n-2) + fib(n-1);
    }
    private int size;
    public Ja15_7(){}
    public Ja15_7(int size){this.size=size;}
    public Iterator<Integer> iterator(){
        return new Iterator<Integer>(){
            public boolean hasNext(){return size>0;}
            public Integer next(){size--;return Ja15_7.this.next();}
            public void remove(){throw new RuntimeException();}

        };
    }
    public static void main(String[] args) {
        Ja15_7 gen = new Ja15_7();
        for(int i = 0; i < 18; i++)
            System.out.print(gen.next() + " ");
        for(Integer in:new Ja15_7(5))
            System.out.println(in);
    }
}

練習8:

/* Following the form of the Coffee example, create a hierarchy of StoryCharacter(s) from 
 * your favorite movie, dividing them into GoodGuy(s) and BadGuy(s). Create a generator
 * for StoryCharacter(s), following the form of CoffeeGenerator.*/
import java.util.*;
interface Generator<T>{
    public T next();
}
class Guy{
    private static int count=0;
    private final int id=count++;
    public String toSting(){return getClass().getSimpleName()+"  "+id;}
}
class GoodGuy extends Guy{}
class BadGuy extends Guy{}
public class Ja15_8 implements Generator<Guy>{
    private static Class[] types={GoodGuy.class,BadGuy.class};
    Random rand=new Random(55);
    public Guy next(){
        try{
            return (Guy)types[rand.nextInt(types.length)].newInstance();
        }catch(Exception e){
            throw new RuntimeException(e);
        }

    }
    public static void main(String[] args){
        Ja15_8 gen=new Ja15_8();
        for(int i=0;i<3;i++)System.out.println(gen.next());
    }
}

練習9:

// Modify GenericMethods so that f() accepts three arguments, all 
// of which are of a different parameterized type.
public class Ja15_9 {
  public <T,U,V> void f(T x,U u,V v) {
    System.out.println(x.getClass().getName());
    System.out.println(u.getClass().getName());
    System.out.println(v.getClass().getName());
  }
  public static void main(String[] args) {
    Ja15_9 gm = new Ja15_9();
    gm.f(gm,1.0f,'c');
  }
} 

練習10:

// Modify the previous exercise so that one of f()'s arguments
// is non-parameterized.
public class Ja15_10{
  public <T,U,V> void f(T x,U u,V v,Integer i) {
    System.out.println(x.getClass().getName());
    System.out.println(u.getClass().getName());
    System.out.println(v.getClass().getName());
    System.out.println(i.getClass().getName());
  }
  public static void main(String[] args) {
    Ja15_10 gm = new Ja15_10();
    gm.f(1.0f,'c',gm,1);
  }
} 

練習11:

// Test New.java by creating your own classes and ensuring that
// New will work properly with them.
import java.util.*;

public class Ja15_11 {
  public static <K,V> Map<K,V> map() {
    return new HashMap<K,V>();
  }
  public static <T> List<T> list() {
    return new ArrayList<T>();
  }
  public static <T> LinkedList<T> lList() {
    return new LinkedList<T>();
  }
  public static <T> Set<T> set() {
    return new HashSet<T>();
  }	
  public static <T> Queue<T> queue() {
    return new LinkedList<T>();
  }
  // Examples:
  public static void main(String[] args) {
    Map<Integer,Map<Integer,String>> sls = Ja15_11.map();
    List<String> ls = Ja15_11.list();
    LinkedList<String> lls = Ja15_11.lList();
    Set<String> ss = Ja15_11.set();
    Queue<String> qs = Ja15_11.queue();
  }
}

練習12:

// Repeat the previous exercise using explicit type specification.

import java.util.*;

public class Ja15_12 {
  public static <K,V> Map<K,V> map() {
    return new HashMap<K,V>();
  }
  public static <T> List<T> list() {
    return new ArrayList<T>();
  }
  public static <T> LinkedList<T> lList() {
    return new LinkedList<T>();
  }
  public static <T> Set<T> set() {
    return new HashSet<T>();
  }	
  public static <T> Queue<T> queue() {
    return new LinkedList<T>();
  }
  // Examples:
  public static void f(Map<String,List<Integer>> a){}
  public static void main(String[] args) {
      f(Ja15_12.<String,List<Integer>>map());
    Map<Integer,Map<Integer,String>> sls = Ja15_11.map();
    List<String> ls = Ja15_11.list();
    LinkedList<String> lls = Ja15_11.lList();
    Set<String> ss = Ja15_11.set();
    Queue<String> qs = Ja15_11.queue();
  }
}


練習13:

/* Overload the fill() method so that the arguments and return types are
* the specific subtypes of Collection: List, Queue and Set. This way, you
* don't lose the type of container. Can you overload to distinguish between
* List and LinkedList?
*/
import generics.coffee.*;
import java.util.*;
import net.mindview.util.*;

public class Ja15_13 {
    /*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> Set<T> fill(Set<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> coll,Generator<T> gen,int n){
        for(int i = 0; i < n; i++)
            coll.add(gen.next());
        System.out.println("List Only");//可以區分List和LinkedList
        
        return coll;
    }
    public static <T> LinkedList<T> fill(LinkedList<T> coll,Generator<T> gen,int n){
        for(int i = 0; i < n; i++)
            coll.add(gen.next());
        System.out.println("LinkedList");

        return coll;
    }
    public static void main(String[] args) {
        /*Collection<Coffee> coffee = fill(
                new ArrayList<Coffee>(), new CoffeeGenerator(), 4);
        for(Coffee c : coffee)
            System.out.println(c);*/
        Collection<Coffee> c1 = fill(
                new ArrayList<Coffee>(), new CoffeeGenerator(), 4);
        for(Coffee c : c1)
            System.out.println(c);
        Collection<Coffee> c2 = fill(
                new LinkedList<Coffee>(), new CoffeeGenerator(), 4);
        for(Coffee c : c2)
            System.out.println(c);
        /*Collection<Integer> fnumbers = fill(
                new ArrayList<Integer>(), new Fibonacci(), 12);
        for(int i : fnumbers)
            System.out.print(i + ", ");*/
    }
} 

練習14:

/* Modify BasicGeneratorDemo.java to use the explicit form of creation for the
* Generator (that is, use the explict constructor instead of the generic 
* create() method). 
*/
import net.mindview.util.*;
import generics.*;

public class Ja15_14 {
  public static void main(String[] args) {
      BasicGenerator<CountedObject> ge=new BasicGenerator<CountedObject>(CountedObject.class);
    //Generator<CountedObject> gen =
      //BasicGenerator.create(CountedObject.class);
    for(int i = 0; i < 5; i++)
      System.out.println(ge.next());
  }
}

練習15:

/* ... if you were to try to capture the result of f2() into a 
* paramterized TwoTuple, the compiler would issue a warning.
* Verify the previous statement.
*/
import net.mindview.util.*;
import static net.mindview.util.Tuple.*;
import typeinfo.pets.*;

public class Ja15_15 {
  static TwoTuple<String,Integer> f() {
    return tuple("hi", 47);
  }
  static TwoTuple f2() { return tuple("hi", 47); }
  /*static ThreeTuple<Pug,String,Integer> g() {
    return tuple(new Pug(), "hi", 47);
  }*/
  static
  FourTuple<Dog,Pug,String,Integer> h() {
    return tuple(new Dog(), new Pug(), "hi", 47);
  }
  static
  FiveTuple<Dog,Pug,String,Integer,Double> k() {
    return tuple(new Dog(), new Pug(),
      "hi", 47, 11.1);
  }
  public static void main(String[] args) {
    TwoTuple<String,Integer> ttsi = f();
    /*編譯器警告未經審查*/
    TwoTuple<String,Integer> ttsi2 = f2();
    System.out.println(ttsi);
    System.out.println(f2());
    //System.out.println(g());
    System.out.println(h());
    System.out.println(k());
  }
}

練習16:

// Add a SixTuple to Tuple.java and test it in TupleTest2.java.
import net.mindview.util.*;
import static net.mindview.util.Tuple.*;
import typeinfo.pets.*;

public class Ja15_16 {
  static TwoTuple<String,Integer> f() {
    return tuple("hi", 47);
  }
  static TwoTuple f2() { return tuple("hi", 47); }
  /*static ThreeTuple<Pug,String,Integer> g() {
    return tuple(new Pug(), "hi", 47);
  }*/
  static
  FourTuple<Dog,Pug,String,Integer> h() {
    return tuple(new Dog(), new Pug(), "hi", 47);
  }
  static
  FiveTuple<Dog,Pug,String,Integer,Double> k() {
    return tuple(new Dog(), new Pug(),
      "hi", 47, 11.1);
  }
  static SixTuple<Dog,Pug,String,Integer,Double,Cat> j(){
    return tuple(new Dog(), new Pug(), "hi", 47, 11.1,new Cat());
  }
  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(j());
  }
}

練習17:

???

練習18:

// Following the form of BankTeller.java, create an example where
// BigFish eat LittleFish in the ocean.
import static net.mindview.util.Print.*;
class Generator<T>{

}
class BigFish{
    private BigFish(){}
    public static Generator<BigFish> generator(){
        return new Generator<BigFish>(){
            public BigFish next(){return new BigFish();}
            public String toString(){
                return "BigFish";
            }
        };
    }
}
class LittleFish{
    private LittleFish(){}
    public static Generator<LittleFish> generator=new Generator<LittleFish>(){
        public LittleFish next(){
            return new LittleFish();
        }
            public String toString(){
                return "LittleFish";
            }
    };
}
public class Ja15_18{
    public static void main(String[] args){
        print(BigFish.generator());
        print(LittleFish.generator);
    }
}

練習19:

// Following the form of Store.java, build a model of a containerized 
// cargo ship.
import static net.mindview.util.Print.*;
import java.util.*;
import  net.mindview.util.*;
import generics.*;
class A{
    private static int count=0;
    private final int id=count++;
    public String toString(){return "A"+id;}
    public static Generator<A> generator=new Generator<A>(){
        public A next(){
            return new A();
        }

    };
}
class B extends ArrayList<A>{
    public B(int a){
        //for(int i=0;i<a;i++)add(new A());
    Generators.fill(this,A.generator,a);
    }
}
class C extends ArrayList<B>{
    public C(int b,int a){
        for(int i=0;i<b;i++)add(new B(a));
    }
}
public class Ja15_19 extends ArrayList<C>{
    public Ja15_19(int c,int b,int a){
        for(int i=0;i<c;i++)add(new C(b,a));
    }
    public String toString(){
        StringBuilder result=new StringBuilder();
        for(C c:this)
            for(B b:c)
                for(A a:b){
                    result.append(a);
                    result.append("\n");
                }
        return result.toString();
    }
    public static void main(String[] args){
        print(new Ja15_19(5,4,3));
    }
}
PS:一定要和generators放在一個資料夾內??

練習20:

/* Create an interface with two methods, and a class that implements that interface
* and adds another method. In another class, create a generic method with an 
* argument type that is bounded by the interface, and show that the methods in the 
* interface are callable inside this generic method. In main(), pass an instance of
* the implementing class to the generic method.
*/
import static net.mindview.util.Print.*;
interface A{
    public void f();
    public void h();

}
class B implements A{
    public void f(){print("f");}
    public void h(){print("h");}
    public void g(){print("g");}
}
class C{
    public <T extends A> void j(T t){t.f();t.h();}//t.g();}
}
public class Ja15_20{
    public static void main(String[] args){
        C c=new C();
        B b=new B();
        c.j(b);
    }
}

練習21:

/* Modify Ja15_21.java by adding a Map<String,Class<?>>,
* a method addType(String typename, Class<?> kind), and a
* method createNew(String typename). creatNew() will either
* produce a new instance of the class associated with its 
* argument string, or produce an error message.
*/
import java.util.*;
import static net.mindview.util.Print.*;
class Building {}
class House extends Building {}

public class Ja15_21<T> {
  Class<T> kind;
  public Ja15_21(Class<T> kind) {
    this.kind = kind;
  }
   Map<String,Class<?>> mm=new LinkedHashMap<String,Class<?>>();

  public void addType(String typename, Class<?> kind) {
		mm.put(typename, kind);
	}
  public void createNew(String typename){
    try{
        print(mm.get(typename).newInstance());
    }catch(Exception e){
        throw new RuntimeException(e);
    }
  }
  public boolean f(Object arg) {
    return kind.isInstance(arg);
  }	
  public static void main(String[] args) {
    Ja15_21<Building> ctt1 =
      new Ja15_21<Building>(Building.class);
    System.out.println(ctt1.f(new Building()));
    System.out.println(ctt1.f(new House()));
    Ja15_21<House> ctt2 =
      new Ja15_21<House>(House.class);
    System.out.println(ctt2.f(new Building()));
    System.out.println(ctt2.f(new House()));
    ctt1.addType("aa",Building.class);
    ctt1.createNew("aa");
  }
} 
PS:若Map的定義忘記加上<>,只會提示“不安全”,卻不指明錯誤在哪。

練習22:

/* Use a type tag along with reflection to create a method that uses the 
* argument version of newInstance() to create an object of a class with
* a constructor that has arguments.
*/
import java.util.*;
import static net.mindview.util.Print.*;
class A{
    public A(Integer i){
        print(i);
    }
    public A(){}
    public String toString(){return ("Congratulations!!");}
}
class B<T>{
    T x;
    public B(Class<?> kind,Integer i,String typename){
        try{
            print(Class.forName(typename).getDeclaredConstructor(i.getClass()).newInstance(i));
            //x=kind.newInstance(i);
            print("x "+i);
        }catch(Exception e){
            throw new RuntimeException(e);
        }
    }
}
public class Ja15_22{
    public static void main(String[] args){
        B<A> b=new B<A>(A.class,2,"A");
    }
}
PS: i.getClass()只能應用於Integer之類,不能是int!

練習23:

// Modify FactoryConstraint.java so that create() takes an argument.
import static net.mindview.util.Print.*;
interface FactoryI<T> {
  T create(Integer i);
}

class Foo2<T> {
  private T x;
  public <F extends FactoryI<T>> Foo2(F factory,Integer i) {
    x = factory.create(i);
  }
  // ...
}

class IntegerFactory implements FactoryI<Integer> {
  public Integer create(Integer i) {
    print(i);
    return new Integer(i);
  }
}	

class Widget {
    public Widget(Integer i){print(i);}
  public static class Factory implements FactoryI<Widget> {
    public Widget create(Integer i) {
      return new Widget(i);
    }
  }
}

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


練習24:

// Modify Exercise 21 so that factory objects are held in the Map instead of Class<?>.
import java.util.*;
import static net.mindview.util.Print.*;
class Building {
    
}
class House extends Building {}
interface Factory<T>{
    T create();   
}
class BuildingFactory implements Factory<Building>{
    public Building create(){return new Building();}
}
class HouseFactory implements Factory<House>{
    public House create(){return new House();}
}
public class Ja15_24<T> {
  Class<T> kind;
  public Ja15_24(Class<T> kind) {
    this.kind = kind;
  }
   Map<String,Factory> mm=new LinkedHashMap<String,Factory>();

  public void addType(String typename, Factory kind) {
		mm.put(typename, kind);
	}
  public void createNew(String typename){
    try{
        print(mm.get(typename).create());
    }catch(Exception e){
        throw new RuntimeException(e);
    }
  }
  public boolean f(Object arg) {
    return kind.isInstance(arg);
  }	
  public static void main(String[] args) {
    Ja15_24<Building> ctt1 =
      new Ja15_24<Building>(Building.class);
    System.out.println(ctt1.f(new Building()));
    System.out.println(ctt1.f(new House()));
    Ja15_24<House> ctt2 =
      new Ja15_24<House>(House.class);
    System.out.println(ctt2.f(new Building()));
    System.out.println(ctt2.f(new House()));
    ctt1.addType("aa",new HouseFactory());
    ctt1.createNew("aa");
  }
} 


練習25:

/* Create two interfaces and a class that implements both. Create two
* generic methods, one whose argument parameter is bounded by the first
* interface and one whose argument parameter is bounded by the second
* interface. Create an instance of the class that implements both 
* interfaces, and show that it can be used with both generic methods.
*/
import static net.mindview.util.Print.*;
interface A{void a();}
interface B{void b();}

class C implements A,B{
    public void a(){print("aa");}
    public void b(){print("bb");}

    <T extends A> void f(T a){a.a();} //A和B相當於是上邊界,Object類在這個上邊界之上
    <T extends B> void g(T b){b.b();}
    <T> void m(T m){print("T m");}
}
class D extends C{}
public class Ja15_25{
    public static void main(String[] args){
        C c=new C();
        c.f(new C());
        c.g(new C());
        c.f(new D());
        c.m(new Object());
        
        
    }
}

練習26:

// Demonstrate array covariance using Numbers and Integers.
import static net.mindview.util.Print.*;
public class Ja15_26{
    public static void main(String[] args){
        Number[] nu=new Number[3];
        nu[0]=new Integer(0);//OK
        nu[1]=new Double(3.3);//OK
        nu[0]=new Double(3.6);//OK??
        print(nu[0]);
        Number[] in=new Integer[3];//這就是協變型別
        //in[0]=new Number(8); //abstract class
        in[0]=new Integer(0);
        System.out.print(in[0].getClass().getSimpleName());
        //in[1]=new Double(2.2);//Runtime ArrayStoreException

    }
}

練習27:

// Show that covariancd doesn't work with Lists using Numbers and 
// Integers, then introduce wildcards.
import java.util.*;

public class Ja15_27 {
	public static void main(String[] args) {
		// compile error: incompatible types:
		// List<Number> lnum = new ArrayList<Integer>();
		List<? extends Number> nlist = new ArrayList<Integer>();
		// compile error: can't add Integer:
		// nlist.add(new Integer(0));
		nlist.add(null); // can add null
		Number x = nlist.get(0); // can get Number (null)
		System.out.println(nlist);
	}	
}

練習28:

/* Create a generic class Generic1<T> with a single method that takes an argument
* of type T. Create a second generic class Generic2<T> with a single method that 
* returns an argument of type T. Write a generic method with a contravariant 
* argument of the first generic class that calls its method. Write a second generic
* method with a covariant argument of the second class that calls its method. Test
* using the typeinfo.pets library.
*/
import typeinfo.pets.*;

import static net.mindview.util.Print.*;

public class Ja15_28{
    class Generic1<T>{
        T t;
        <T> void f1(T t){}
    }
    class Generic2<T>{
        T t;
        T f2(){return t;}
    }
    <T> void contra(Generic1<? super T> g,T t){
        g.f1(t);
    }
    <T> void co(Generic2<? extends T> g2){
        print(g2.f2());
    }

    public static void main(String[] args){
        Ja15_28 j=new Ja15_28();
        j.contra(j.new Generic1<Pet>(),new Dog("dogy"));
        j.co(j.new Generic2<Pet>());
    }
}


練習29:

/* Create a generic method that takes as an argument a Holder<List<?>>. 
 * Determine what methods you can and can't call for the Holder and for
 * the List. Repeat for an argument of List<Holder<?>>.
 */
import generics.*;
import static net.mindview.util.Print.*;
import java.util.*;
class Fruit{}
class Apple extends Fruit{}
class Orange extends Fruit{}
class Holder<T> {
  private T value;
  public Holder() {}
  public Holder(T val) { value = val; }
  public void set(T val) { value = val; }
  public T get() { return value; }
  public boolean equals(Object obj) {
    return value.equals(obj);
  }	
  public static void main(String[] args) {
    Holder<Apple> Apple = new Holder<Apple>(new Apple());
    Apple d = Apple.get();
    Apple.set(d);
    // Holder<Fruit> Fruit = Apple; // Cannot upcast
    Holder<? extends Fruit> fruit = Apple; // OK
    Fruit p = fruit.get();
    d = (Apple)fruit.get(); // Returns 'Object'-->'Apple'?
    System.out.println(d.getClass().getSimpleName());
    try {
      Orange c = (Orange)fruit.get(); // No warning
    } catch(Exception e) { System.out.println(e); }
    // fruit.set(new Apple()); // Cannot call set()
    // fruit.set(new Fruit()); // Cannot call set()
    System.out.println(fruit.equals(d)); // OK
  }
}

public class Ja15_29{
    static void f(Holder<List<?>> h){
        h.set(new ArrayList<Integer>());
        print(h.get().getClass().getSimpleName());
    }
    public static void main(String[] args){
        Holder<List<?>> h=new Holder<List<?>>();
        f(h);
        Holder<List<?>> h2=new Holder<List<?>>();
        f(h2);
    }
}

練習30:

// Create a Holder for each of the primitive wrapper types, and show that
// autoboxing and autounboxing works for the set() and get() methods of 
// each instance.
import static net.mindview.util.Print.*;
public class Ja15_30{
    public static void main(String[] args){
        Holder<Integer> h=new Holder<Integer>();
        int i=4;
        h.set(i);
        print(h.get().getClass());
    }
}

練習31:

// Remove all generics from MultipleInterfaceVariants.java and modify
// the code so that the example compiles.

interface Payable<T> {}

class Employee implements Payable  {}
class Hourly extends Employee implements Payable {} ///:~



練習32:

/*
* Verify that FixedSizeStack in GenericCast.java generates exceptions
* if you try to go out of its bounds. Does this mean that bounds-checking
* code is not required?
*/
//: generics/GenericCast.java

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]; }
}	

public class Ja15_32 {
  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);
    //RuntimeException
    //strings.push("fsd");
    for(int i = 0; i < SIZE; i++) {
      String s = strings.pop();
      System.out.print(s + " ");
    }
  }
} 

練習33:

// Repair GenericCast.java using an ArrayList.
import java.util.*;
class FixedSizeStack<T> {
    private int index = 0;
    private List<T> storage=new ArrayList<T>();
    public FixedSizeStack() {
      
      }
    public void push(T item) { storage.add(item);}
    @SuppressWarnings("unchecked")
    public int count(){return storage.size();}
    public T pop() { return (T)storage.remove(storage.size()-1); }
}	

public class Ja15_33 {
    public static void main(String[] args) {
        FixedSizeStack<String> strings =
            new FixedSizeStack<String>();
        for(String s : "A B C D E F G H I J".split(" "))
            strings.push(s);
        int count = strings.count();
        for(int i=0;i<count;i++){String s = strings.pop();
        System.out.print(s + " ");}
    }
}
 


練習34:

/* Create a self-bounded generic type that contains an abstract method
* that takes an argument of the generic type parameter and produces a
* return value of the generic type parameter. In a non-abstract method
* of the class, call the abstract method and return its result. Inherit
* from the self-bounded type and test the resulting class.
*/
abstract class A<T extends A<T>>{
    abstract T f(T a);
    T h(T t){return f(t);}
}
class B extends A<B>{
    B f(B b){return b;}

}
public class Ja15_34{
    public static void main(String[] args){
        B m=new B();
        m.h(new B());
    }
}

練習35:

// Modify CheckedList.java so that it uses the Coffee classes defined
import java.util.Collections.*;
import java.util.*;
import generics.coffee.*;
public class Ja15_35{
    public static void main(String[] args){
        Set<Latte> la=Collections.checkedSet(new  HashSet<Latte>(),Latte.class);
        la.add(new Latte());
        //la.add(new Coffee());
    }
}



練習36:

// Add a second parameterized exception to the Processor class and 
// demonstrate that the exceptions can vary independently.
import java.util.*;

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

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

class Failure1 extends Exception {}
class Failure3 extends Exception {}

class Processor1 implements Processor<String,Failure1,Failure3> {
  static int count = 3;
  public void
  process(List<String> resultCollector) throws Failure1,Failure3 {
    if(count-- > 1)
      resultCollector.add("Hep!");
    else
      resultCollector.add("Ho!");
    if(count < 0&&count>-1)
    {throw new Failure1();}
    if(count<-1){throw new Failure3();}
  }
}	

class Failure2 extends Exception {}
class Failure4 extends Exception {}

class Processor2 implements Processor<Integer,Failure2,Failure4> {
  static int count = 2;
  public void
  process(List<Integer> resultCollector) throws Failure2,Failure4 {
    if(count-- == 0)
      resultCollector.add(47);
    else {
      resultCollector.add(11);
    }
    if(count < 0&&count>-1)
    {throw new Failure2();}
    if(count<-1){throw new Failure4();}
  }
}	

public class Ja15_36{
  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 e) {
      System.out.println(e);
    }catch(Failure3 e){}

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

  }
} 


練習37:

練習38:

// generics/CoffeeDecoration38.java
// TIJ4 Chapter Generics, Exercise 38, page 719
// Create a simple Decorator system by starting with basic coffee, then
// providing decorators of steamed milk, foam, chocolate, caramel and 
// whipped cream.
import static net.mindview.util.Print.*;
import generics.coffee.*;
import java.util.*;

class BasicCoffee {
	private static long counter = 0;
  	private final long id = counter++;
	private String value;
	public void set(String val) { value = val; }
	public String get() { return value; }
  	public String toString() {
    		return getClass().getSimpleName() + " " + id;
  	}
}

class Decorator extends BasicCoffee {
	protected BasicCoffee basicCoffee;
	public Decorator(BasicCoffee basicCoffee) { 
		this.basicCoffee = basicCoffee; 
	}
	public void set(String val) { basicCoffee.set(val); }
	public String get() { return basicCoffee.get(); }
}

class SteamedMilk extends Decorator {
	private final String steamedMilk = "steamedMilk";
	public SteamedMilk(BasicCoffee basicCoffee) {
		super(basicCoffee);
	}
	public String getSteamedMilk() { return steamedMilk; }
}

class Foam extends Decorator {
	private final String foam = "foam";
	public Foam(BasicCoffee basicCoffee) {
		super(basicCoffee);
	}
	public String getFoam() { return foam; }
}

class Chocolate extends Decorator {
	private final String chocolate = "chocolate";
	public Chocolate(BasicCoffee basicCoffee) {
		super(basicCoffee);
	}
	public String getChocolate() { return chocolate; }
}

class Caramel extends Decorator {
	private final String caramel = "caramel";
	public Caramel(BasicCoffee basicCoffee) {
		super(basicCoffee);
	}
	public String getCaramel() { return caramel; }
}

class WhippedCream extends Decorator {
	private final String whippedCream = "whippedCream";
	public WhippedCream(BasicCoffee basicCoffee) {
		super(basicCoffee);
	}
	public String getWhippedCream() { return whippedCream; }
}

public class Ja15_38{
	public static void main(String[] args) {
		SteamedMilk sm = new SteamedMilk(new BasicCoffee());
		SteamedMilk sm2 = new SteamedMilk(
			new Foam(new BasicCoffee()));
		Chocolate c = new Chocolate(new BasicCoffee());
		WhippedCream wc = new WhippedCream(new Caramel(
			new Chocolate(new Foam(new SteamedMilk(
			new BasicCoffee())))));
        print(wc.getCaramel());
	}
}

練習39:

//: generics/DynamicProxyMixin.java
import java.lang.reflect.*;
import java.util.*;
import net.mindview.util.*;
import static net.mindview.util.Tuple.*;

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));
  }
}	
class Colored{
    public String get(){return "Colored";}
}
public class DynamicProxyMixin {
    @SuppressWarnings("unchecked")
  public static void main(String[] args) {
    Object mixin = MixinProxy.newInstance(
      tuple(new BasicImp(), Basic.class),
      tuple(new TimeStampedImp(), TimeStamped.class),
      tuple(new Colored(),Colored.class),
      tuple(new SerialNumberedImp(),SerialNumbered.class));
  @SuppressWarnings("unchecked")
    Basic b = (Basic)mixin;
    TimeStamped t = (TimeStamped)mixin;
    Colored c=(Colored)mixin;

    SerialNumbered s = (SerialNumbered)mixin;

    b.set("Hello");
    System.out.println(b.get());
    System.out.println(t.getStamp());
    System.out.println(c.get());
    System.out.println(s.getSerialNumber());
  }
} /* Output: (Sample)
Hello
1132519137015
1
*///:~

PS:無法通過安全檢查?(哪怕用了@SuppressWarnings)

練習40:

// Add a speak() method to all the pets in tyepinfo.pets. Modify Apply.java to call the speak
// method for a heterogeneous collection of Pet.
//: generics/Apply.java
// {main: ApplyTest}
import java.lang.reflect.*;
import java.util.*;
import static net.mindview.util.Print.*;
import typeinfo.pets.*;

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);
    }
  }
}	

class Shape {
  public void rotate() { print(this + " rotate"); }
  public void resize(int newSize) {
    print(this + " resize " + newSize);
  }
}

class Square extends Shape {}

class FilledList<T> extends ArrayList<T> {
  public FilledList(Class<? extends T> type, int size) {
    try {
      for(int i = 0; i < size; i++)
        // Assumes default constructor:
        add(type.newInstance());
    } catch(Exception e) {
      throw new RuntimeException(e);
    }
  }
}	

public class Ja15_40{
  public static void main(String[] args) throws Exception {
    List<Shape> shapes = new ArrayList<Shape>();
    for(int i = 0; i < 10; i++)
      shapes.add(new Shape());
    Apply.apply(shapes, Shape.class.getMethod("rotate"));
    Apply.apply(shapes,
      Shape.class.getMethod("resize", int.class), 5);
    List<Square> squares = new ArrayList<Square>();
    for(int i = 0; i < 10; i++)
      squares.add(new Square());
    Apply.apply(squares, Shape.class.getMethod("rotate"));
    Apply.apply(squares,
      Shape.class.getMethod("resize", int.class), 5);
	
    Apply.apply(new FilledList<Shape>(Shape.class, 10),
      Shape.class.getMethod("rotate"));
    Apply.apply(new FilledList<Shape>(Square.class, 10),
      Shape.class.getMethod("rotate"));


    List<Pet> lp=new ArrayList<Pet>();
    lp.add(new Dog());
    lp.add(new Cat());
    lp.add(new Pug());

    Apply.apply(lp,Pet.class.getMethod("speak"));
  }
} /* (Execute to see output) *///:~


練習41:

// Modify Fill2.java to use the classes in typeinfo.pets instead
// of the Pet classes.
// Using adapters to simulate latent typing.
// {main: Fill41Test}
import generics.coffee.*;
import java.util.*;
import net.mindview.util.*;
import static net.mindview.util.Print.*;
import typeinfo.pets.*;

interface Addable<T> { void add(T t); }
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();
  }
}
class Fill2 {
  // Classtoken version:
  public static <T> 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);
      }
  }
  // Generator version:
  /*public static <T> void fill(Addable<T> addable,
  Generator<T> generator, int size) {
    for(int i = 0; i < size; i++)
      addable.add(generator.next());
  }*/
}

// To adapt a base type, you must use composition.
// Make any Collection Addable using composition:
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); }
}
	
// A Helper to capture the type automatically:
class Adapter {
  public static <T>
  Addable<T> collectionAdapter(Collection<T> c) {
    return new AddableCollectionAdapter<T>(c);
  }
}

// To adapt a specific type, you can use inheritance.
// Make a SimpleQueue Addable using inheritance:
class AddableSimpleQueue<T>
extends SimpleQueue<T> implements Addable<T> {
  public void add(T item) { super.add(item); }
}
	
public class Ja15_41{
  public static void main(String[] args) {
    // Adapt a Collection:
    List<Pet> carrier = new ArrayList<Pet>();
    Fill2.fill(
      new AddableCollectionAdapter<Pet>(carrier),
      Pet.class, 3);
    // Helper method captures the type:
    Fill2.fill(Adapter.collectionAdapter(carrier),
      Dog.class, 2);
    for(Pet c: carrier)
      print(c);
    print("----------------------");
    // Use an adapted class:
    AddableSimpleQueue<Pet> coffeeQueue =
      new AddableSimpleQueue<Pet>();
    Fill2.fill(coffeeQueue, Pug.class, 4);
    Fill2.fill(coffeeQueue,Dog.class, 1);
    for(Pet c: coffeeQueue)
      print(c);
  }
} 

練習42:

/*
* Create two separate classes, with nothing in common. Each class should 
* hold a value, and at least have methods that produce that value and 
* perform a modification upon that value. Modify Functional.java so that
* it performs functional operations on collections of your classes (these
* operations do not have to be arithmetic as they are in Functional.java).
*/
import typeinfo.pets.*;
import java.math.*;
import java.util.concurrent.atomic.*;
import java.util.*;
import static net.mindview.util.Print.*;

// Different types of function objects:
interface Combiner<T> { T combine(T x, T y); }
interface UnaryFunction<R,T> { R function(T x); }
interface Collector<T> extends UnaryFunction<T,T> {
  T result(); // Extract result of collecting parameter
}
interface UnaryPredicate<T> { boolean test(T x); }
class A implements UnaryPredicate<Pet>{
    public boolean test(Pet p){return p.getClass().getSimpleName().equals("Pet");};
}	
class B implements UnaryPredicate<Dog>{
    public boolean test(Dog p){return p.getClass().getSimpleName().equals("Dog");};
}
public class Ja15_42 {
  // Calls the Combiner object on each element to combine
  // it with a running result, which is finally returned:
  public static <T> T
  reduce(Iterable<T> seq, Combiner<T> combiner) {
    Iterator<T> it = seq.iterator();
    if(it.hasNext()) {
      T result = it.next();
      while(it.hasNext())
        result = combiner.combine(result, it.next());
      return result;
    }
    // If seq is the empty list:
    return null; // Or throw exception
  }
  // Take a function object and call it on each object in
  // the list, ignoring the return value. The function
  // object may act as a collecting parameter, so it is
  // returned at the end.
  public static <T> Collector<T>
  forEach(Iterable<T> seq, Collector<T> func) {
    for(T t : seq)
      func.function(t);
    return func;
  }
  // Creates a list of results by calling a
  // function object for each object in the list:
  public static <R,T> List<R>
  transform(Iterable<T> seq, UnaryFunction<R,T> func) {
    List<R> result = new ArrayList<R>();
    for(T t : seq)
      result.add(func.function(t));
    return result;
  }
  // Applies a unary predicate to each item in a sequence,
  // and returns a list of items that produced "true":
  public static <T> List<T>
  filter(Iterable<T> seq, UnaryPredicate<T> pred) {
    List<T> result = new ArrayList<T>();
    for(T t : seq)
      if(pred.test(t))
        result.add(t);
    return result;
  }
  // To use the above generic methods, we need to create
  // function objects to adapt to our particular needs:
  static class IntegerAdder implements Combiner<Integer> {
    public Integer combine(Integer x, Integer y) {
      return x + y;
    }
  }
  static class
  IntegerSubtracter implements Combiner<Integer> {
    public Integer combine(Integer x, Integer y) {
      return x - y;
    }
  }
  static class
  BigDecimalAdder implements Combiner<BigDecimal> {
    public BigDecimal combine(BigDecimal x, BigDecimal y) {
      return x.add(y);
    }
  }
  static class
  BigIntegerAdder implements Combiner<BigInteger> {
    public BigInteger combine(BigInteger x, BigInteger y) {
      return x.add(y);
    }
  }
  static class
  AtomicLongAdder implements Combiner<AtomicLong> {
    public AtomicLong combine(AtomicLong x, AtomicLong y) {
      // Not clear whether this is meaningful:
      return new AtomicLong(x.addAndGet(y.get()));
    }
  }
  // We can even make a UnaryFunction with an "ulp"
  // (Units in the last place):
  static class BigDecimalUlp
  implements UnaryFunction<BigDecimal,BigDecimal> {
    public BigDecimal function(BigDecimal x) {
      return x.ulp();
    }
  }
  static class GreaterThan<T extends Comparable<T>>
  implements UnaryPredicate<T> {
    private T bound;
    public GreaterThan(T bound) { this.bound = bound; }
    public boolean test(T x) {
      return x.compareTo(bound) > 0;
    }
  }
  static class MultiplyingIntegerCollector
  implements Collector<Integer> {
    private Integer val = 1;
    public Integer function(Integer x) {
      val *= x;
      return val;
    }
    public Integer result() { return val; }
  }
  public static void main(String[] args) {
    // Generics, varargs & boxing working together:
    List<Integer> li = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
    Integer result = reduce(li, new IntegerAdder());
    print(result);

    result = reduce(li, new IntegerSubtracter());
    print(result);

    print(filter(li, new GreaterThan<Integer>(4)));

    print(forEach(li,
      new MultiplyingIntegerCollector()).result());

    print(forEach(filter(li, new GreaterThan<Integer>(4)),
      new MultiplyingIntegerCollector()).result());

    MathContext mc = new MathContext(7);
    List<BigDecimal> lbd = Arrays.asList(
      new BigDecimal(1.1, mc), new BigDecimal(2.2, mc),
      new BigDecimal(3.3, mc), new BigDecimal(4.4, mc));
    BigDecimal rbd = reduce(lbd, new BigDecimalAdder());
    print(rbd);

    print(filter(lbd,
      new GreaterThan<BigDecimal>(new BigDecimal(3))));

    // Use the prime-generation facility of BigInteger:
    List<BigInteger> lbi = new ArrayList<BigInteger>();
    BigInteger bi = BigInteger.valueOf(11);
    for(int i = 0; i < 11; i++) {
      lbi.add(bi);
      bi = bi.nextProbablePrime();
    }
    print(lbi);

    BigInteger rbi = reduce(lbi, new BigIntegerAdder());
    print(rbi);
    // The sum of this list of primes is also prime:
    print(rbi.isProbablePrime(5));

    List<AtomicLong> lal = Arrays.asList(
      new AtomicLong(11), new AtomicLong(47),
      new AtomicLong(74), new AtomicLong(133));
    AtomicLong ral = reduce(lal, new AtomicLongAdder());
    print(ral);

    print(transform(lbd,new BigDecimalUlp()));

    List<Pet> lp=Arrays.asList(new Pet());
    print(filter(lp,new A()));
    List<Dog> lg=Arrays.asList(new Dog());
    print(filter(lg,new B()));
  }
}