Java基础之十五 泛型
- 2019 年 10 月 3 日
- 笔记
???? ??
???????????????????????????????????????????????????????????????????????
??????????????????????
???????????????????????????
15.2 ????
??????????????
??????????????
class Automobile {} public class Holder1 { private Automobile a; public Holder1(Automobile a) { this.a = a; } Automobile get() { return a; } }
????Object?????,?????????????
public class Holder2 { private Object a; public Holder2(Object a) { this.a = a; } public void set(Object a) { this.a = a; } public Object get() { return a; } public static void main(String[] args) { Holder2 h2 = new Holder2(new Automobile()); Automobile a = (Automobile)h2.get(); h2.set("Not an Automobile"); String s = (String)h2.get(); h2.set(1); // Autoboxes to Integer Integer x = (Integer)h2.get(); } }
???????
public class Holder3<T> { private T a; public Holder3(T a) { this.a = a; } public void set(T a) { this.a = a; } public T get() { return a; } public static void main(String[] args) { Holder3<Automobile> h3 = new Holder3<Automobile>(new Automobile()); Automobile a = h3.get(); // No cast needed // h3.set("Not an Automobile"); // Error // h3.set(1); // Error } }
15.2.1??????
???????????????????????????????????????????????????????
????????????????????????????
//: generics/TupleTest.java import net.mindview.util.*; class Amphibian {} class Vehicle {} public class TupleTest { static TwoTuple<String,Integer> f() { // Autoboxing converts the int to Integer: return new TwoTuple<String,Integer>("hi", 47); } static ThreeTuple<Amphibian,String,Integer> g() { return new ThreeTuple<Amphibian, String, Integer>( new Amphibian(), "hi", 47); } static FourTuple<Vehicle,Amphibian,String,Integer> h() { return new FourTuple<Vehicle,Amphibian,String,Integer>( new Vehicle(), new Amphibian(), "hi", 47); } static FiveTuple<Vehicle,Amphibian,String,Integer,Double> k() { return new FiveTuple<Vehicle,Amphibian,String,Integer,Double>( new Vehicle(), new Amphibian(), "hi", 47, 11.1); } public static void main(String[] args) { TwoTuple<String,Integer> ttsi = f(); System.out.println(ttsi); // ttsi.first = "there"; // Compile error: final System.out.println(g()); System.out.println(h()); System.out.println(k()); } } /* Output: (80% match) (hi, 47) (Amphibian@1f6a7b9, hi, 47) (Vehicle@35ce36, Amphibian@757aef, hi, 47) (Vehicle@9cab16, Amphibian@1a46e30, hi, 47, 11.1) *///:~
15.2.2 ?????
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; } } private Node<T> top = new Node<T>(); // End sentinel public void push(T item) { top = new Node<T>(item, top); } public T pop() { T result = top.item; if(!top.end()) top = top.next; return result; } public static void main(String[] args) { LinkedStack<String> lss = new LinkedStack<String>(); for(String s : "Phasers on stun!".split(" ")) lss.push(s); String s; while((s = lss.pop()) != null) System.out.println(s); } } /* Output: stun! on Phasers *///:~
15.2.3 RandomList
//: generics/RandomList.java import java.util.*; public class RandomList<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) { RandomList<String> rs = new RandomList<String>(); 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() + " "); } } /* Output: brown over fox quick quick dog brown The brown lazy brown *///:~
15.3 ????
????????????????????????????????????????????????????????????????????????????????????
package coffee; public class Americano extends Coffee {} . . .
??Generator< Coffee >??????????????
package coffee; import java.util.*; import net.mindview.util.*; public class CoffeeGenerator implements Generator<Coffee>, Iterable<Coffee> { private Class[] types = { Latte.class, Mocha.class, Cappuccino.class, Americano.class, Breve.class, }; private static Random rand = new Random(47); public CoffeeGenerator() {} // For iteration: private int size = 0; public CoffeeGenerator(int sz) { size = sz; } public Coffee next() { try { return (Coffee) types[rand.nextInt(types.length)].newInstance(); // Report programmer errors at run time: } catch(Exception e) { throw new RuntimeException(e); } } class CoffeeIterator implements Iterator<Coffee> { int count = size; public boolean hasNext() { return count > 0; } public Coffee next() { count--; return CoffeeGenerator.this.next(); } public void remove() { // Not implemented throw new UnsupportedOperationException(); } } public Iterator<Coffee> iterator() { return new CoffeeIterator(); } public static void main(String[] args) { CoffeeGenerator gen = new CoffeeGenerator(); for(int i = 0; i < 5; i++) System.out.println(gen.next()); for(Coffee c : new CoffeeGenerator(5)) System.out.println(c); } }
?????Fibonacci???
import net.mindview.util.*; public class Fibonacci implements Generator<Integer> { private int count = 0; public Integer next() { return fib(count++); } private int fib(int n) { if(n < 2) return 1; return fib(n-2) + fib(n-1); } public static void main(String[] args) { Fibonacci gen = new Fibonacci(); for(int i = 0; i < 18; i++) System.out.print(gen.next() + " "); } }
??????????????????????Java SE5????????????????
??????????
import java.util.*; public class IterableFibonacci extends Fibonacci implements Iterable<Integer> { private int n; public IterableFibonacci(int count) { n = count; } public Iterator<Integer> iterator() { return new Iterator<Integer>() { public boolean hasNext() { return n > 0; } public Integer next() { n--; return IterableFibonacci.this.next(); } public void remove() { // Not implemented throw new UnsupportedOperationException(); } }; } public static void main(String[] args) { for(int i : new IterableFibonacci(18)) System.out.print(i + " "); } }
15.4 ????
?????????????????????????????????????static????????????????????static???????????????????????
????????????????????????
public class GenericMethods { public <T> void f(T x) { System.out.println(x.getClass().getName()); } public static void main(String[] args) { GenericMethods gm = new GenericMethods(); gm.f(""); gm.f(1); gm.f(1.0); gm.f(1.0F); gm.f('c'); gm.f(gm); } } /* Output: java.lang.String java.lang.Integer java.lang.Double java.lang.Float java.lang.Character GenericMethods *///:~
?????????????????????????????????????????
???????????????????????????????????????????
15.4.1 ??????????
????????????????static??????????????
public class New { public static <K,V> Map<K,V> map(){ return new HashMap<K,V>(); } }
import pets.*; import java.util.*; import net.mindview.util.*; public class SimplerPets { public static void main(String[] args) { Map<Person, List<? extends Pet>> petPeople = New.map(); // Rest of the code is the same... } } ///:~
?????????????????????????????????????????????????????????????????????????????????????????Object??????
???????
????????????????????????????????????????
import pets.*; import java.util.*; import net.mindview.util.*; public class ExplicitTypeSpecification { static void f(Map<Person, List<Pet>> petPeople) {} public static void main(String[] args) { f(New.<Person, List<Pet>>map()); } } ///:~
15.4.2 ?????????
???????????????????
import java.util.*; public class GenericVarargs { public static <T> List<T> makeList(T... args) { List<T> result = new ArrayList<T>(); for(T item : args) result.add(item); return result; } public static void main(String[] args) { List<String> ls = makeList("A"); System.out.println(ls); ls = makeList("A", "B", "C"); System.out.println(ls); ls = makeList("ABCDEFFHIJKLMNOPQRSTUVWXYZ".split("")); System.out.println(ls); } } /* Output: [A] [A, B, C] [, A, B, C, D, E, F, F, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z] *///:~
15.4.3 ??Generator?????
import coffee.*; import java.util.*; import net.mindview.util.*; public class Generators { 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 void main(String[] args) { Collection<Coffee> coffee = fill( new ArrayList<Coffee>(), new CoffeeGenerator(), 4); for(Coffee c : coffee) System.out.println(c); Collection<Integer> fnumbers = fill( new ArrayList<Integer>(), new Fibonacci(), 12); for(int i : fnumbers) System.out.print(i + ", "); } } /* Output: Americano 0 Latte 1 Americano 2 Mocha 3 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, *///:~
15.4.4 ?????Generator
public class CountedObject { private static long counter = 0; private final long id = counter++; public long id() { return id; } public String toString() { return "CountedObject " + id;} } ///:~
import net.mindview.util.*; public class BasicGeneratorDemo { public static void main(String[] args) { Generator<CountedObject> gen = BasicGenerator.create(CountedObject.class); for(int i = 0; i < 5; i++) System.out.println(gen.next()); } } /* Output: CountedObject 0 CountedObject 1 CountedObject 2 CountedObject 3 CountedObject 4 *///:~
15.4.5 ???????
//: generics/TupleTest2.java import net.mindview.util.*; import static net.mindview.util.Tuple.*; public class TupleTest2 { static TwoTuple<String,Integer> f() { return tuple("hi", 47); } static TwoTuple f2() { return tuple("hi", 47); } static ThreeTuple<Amphibian,String,Integer> g() { return tuple(new Amphibian(), "hi", 47); } static FourTuple<Vehicle,Amphibian,String,Integer> h() { return tuple(new Vehicle(), new Amphibian(), "hi", 47); } static FiveTuple<Vehicle,Amphibian,String,Integer,Double> k() { return tuple(new Vehicle(), new Amphibian(), "hi", 47, 11.1); } 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()); } } /* Output: (80% match) (hi, 47) (hi, 47) (Amphibian@7d772e, hi, 47) (Vehicle@757aef, Amphibian@d9f9c3, hi, 47) (Vehicle@1a46e30, Amphibian@3e25a5, hi, 47, 11.1) *///:~
15.4.6 ??Set????
15.5 ?????
????????????????????????????Generator???
//: generics/BankTeller.java // A very simple bank teller simulation. import java.util.*; import net.mindview.util.*; class Customer { private static long counter = 1; private final long id = counter++; private Customer() {} public String toString() { return "Customer " + id; } // A method to produce Generator objects: public static Generator<Customer> generator() { return new Generator<Customer>() { public Customer next() { return new Customer(); } }; } } class Teller { private static long counter = 1; private final long id = counter++; private Teller() {} public String toString() { return "Teller " + id; } // A single Generator object: public static Generator<Teller> generator = new Generator<Teller>() { public Teller next() { return new Teller(); } }; } public class BankTeller { public static void serve(Teller t, Customer c) { System.out.println(t + " serves " + c); } public static void main(String[] args) { Random rand = new Random(47); Queue<Customer> line = new LinkedList<Customer>(); Generators.fill(line, Customer.generator(), 15); List<Teller> tellers = new ArrayList<Teller>(); Generators.fill(tellers, Teller.generator, 4); for(Customer c : line) serve(tellers.get(rand.nextInt(tellers.size())), c); } } /* Output: Teller 3 serves Customer 1 Teller 2 serves Customer 2 Teller 3 serves Customer 3 Teller 1 serves Customer 4 Teller 1 serves Customer 5 Teller 3 serves Customer 6 Teller 1 serves Customer 7 Teller 2 serves Customer 8 Teller 3 serves Customer 9 Teller 3 serves Customer 10 Teller 2 serves Customer 11 Teller 4 serves Customer 12 Teller 2 serves Customer 13 Teller 1 serves Customer 14 Teller 1 serves Customer 15 *///:~
15.6 ??????
??????????????????????????
??List???
//: generics/TupleList.java // Combining generic types to make complex generic types. import java.util.*; import net.mindview.util.*; public class TupleList<A,B,C,D> extends ArrayList<FourTuple<A,B,C,D>> { public static void main(String[] args) { TupleList<Vehicle, Amphibian, String, Integer> tl = new TupleList<Vehicle, Amphibian, String, Integer>(); tl.add(TupleTest.h()); tl.add(TupleTest.h()); for(FourTuple<Vehicle,Amphibian,String,Integer> i: tl) System.out.println(i); } } /* Output: (75% match) (Vehicle@11b86e7, Amphibian@35ce36, hi, 47) (Vehicle@757aef, Amphibian@d9f9c3, hi, 47) *///:~
???????????????????
//: generics/Store.java // Building up a complex model using generic containers. import java.util.*; import net.mindview.util.*; //?? class Product { private final int id; private String description; private double price; public Product(int IDnumber, String descr, double price){ id = IDnumber; description = descr; this.price = price; System.out.println(toString()); } public String toString() { return id + ": " + description + ", price: $" + price; } public void priceChange(double change) { price += change; } public static Generator<Product> generator = new Generator<Product>() { private Random rand = new Random(47); public Product next() { return new Product(rand.nextInt(1000), "Test", Math.round(rand.nextDouble() * 1000.0) + 0.99); } }; } //?? class Shelf extends ArrayList<Product> { public Shelf(int nProducts) { Generators.fill(this, Product.generator, nProducts); } } //?? class Aisle extends ArrayList<Shelf> { public Aisle(int nShelves, int nProducts) { for(int i = 0; i < nShelves; i++) add(new Shelf(nProducts)); } } class CheckoutStand {} class Office {} //?? public class Store extends ArrayList<Aisle> { private ArrayList<CheckoutStand> checkouts = new ArrayList<CheckoutStand>(); private Office office = new Office(); public Store(int nAisles, int nShelves, int nProducts) { for(int i = 0; i < nAisles; i++) add(new Aisle(nShelves, nProducts)); } public String toString() { StringBuilder result = new StringBuilder(); for(Aisle a : this) for(Shelf s : a) for(Product p : s) { result.append(p); result.append("n"); } return result.toString(); } public static void main(String[] args) { System.out.println(new Store(14, 5, 10)); } } /* Output: 258: Test, price: $400.99 861: Test, price: $160.99 868: Test, price: $417.99 207: Test, price: $268.99 551: Test, price: $114.99 278: Test, price: $804.99 520: Test, price: $554.99 140: Test, price: $530.99 ... *///:~
15.7 ???????
??????ArrayList.class??????ArrayList< Integer >.class
import java.util.*; public class ErasedTypeEquivalence { public static void main(String[] args) { Class c1 = new ArrayList<String>().getClass(); Class c2 = new ArrayList<Integer>().getClass(); System.out.println(c1 == c2); } } /* Output: true *///:~
//: generics/LostInformation.java import java.util.*; class Frob {} class Fnorkle {} class Quark<Q> {} class Particle<POSITION,MOMENTUM> {} public class LostInformation { public static void main(String[] args) { List<Frob> list = new ArrayList<Frob>(); Map<Frob,Fnorkle> map = new HashMap<Frob,Fnorkle>(); Quark<Fnorkle> quark = new Quark<Fnorkle>(); Particle<Long,Double> p = new Particle<Long,Double>(); System.out.println(Arrays.toString( list.getClass().getTypeParameters())); System.out.println(Arrays.toString( map.getClass().getTypeParameters())); System.out.println(Arrays.toString( quark.getClass().getTypeParameters())); System.out.println(Arrays.toString( p.getClass().getTypeParameters())); } } /* Output: [E] [K, V] [Q] [POSITION, MOMENTUM] *///:~
??????????????????????????
Java?????????????????????????????????????????????????????????
15.7.1 C++???
public class HasF { public void f() { System.out.println("HasF.f()"); } } ///:~
//: generics/Manipulation.java // {CompileTimeError} (Won't compile) class Manipulator<T> { private T obj; public Manipulator(T x) { obj = x; } // Error: cannot find symbol: method f(): public void manipulate() {/* obj.f();??????*/ } } public class Manipulation { public static void main(String[] args) { HasF hf = new HasF(); Manipulator<HasF> manipulator = new Manipulator<HasF>(hf); manipulator.manipulate(); } } ///:~
]???????Java??????manipulate()?????obj???f()???????HasF??f()?????
????f()?????extends????
class Manipulator2<T extends HasF> { private T obj; public Manipulator2(T x) { obj = x; } public void manipulate() { obj.f(); } } ///:~
???????????????????????????????????????????????????????????????T????HasF???????????HasF???T???
?????????????????????????——?????????????????????
class ReturnGenericType<T extends HasF> { private T obj; public ReturnGenericType(T x) { obj = x; } public T get() { return obj; } } ///:~
15.7.2 ?????
????????????????????????????????????Java??????????????????Java???????????
?????????????????????????????????????????????????????????????????????????????????????????????????????List< T >????????????List??????????????????????Object?
???????????????????????????????????????
15.7.3 ?????
???????????????????????????????????????????????Java???
?????
class Foo<T>{ T var; } Foo<Cat> f=new Foo<Cat>();
????????????????T??????????????????????????Object?
//: generics/ErasureAndInheritance.java class GenericBase<T> { private T element; public void set(T arg) { arg = element; } public T get() { return element; } } class Derived1<T> extends GenericBase<T> {} class Derived2 extends GenericBase {} // No warning // class Derived3 extends GenericBase<?> {} // Strange error: // unexpected type found : ? // required: class or interface without bounds public class ErasureAndInheritance { @SuppressWarnings("unchecked") public static void main(String[] args) { Derived2 d2 = new Derived2(); Object obj = d2.get(); d2.set(obj); // Warning here! } } ///:~
@SuppressWarnings("unchecked")
??????????????????????????????????????????????????????????????????????????????
15.7.4 ??????
???????????????????????????????????
//: generics/ArrayMaker.java import java.lang.reflect.*; import java.util.*; public class ArrayMaker<T> { private Class<T> kind; public ArrayMaker(Class<T> kind) { this.kind = kind; } @SuppressWarnings("unchecked") T[] create(int size) { return (T[])Array.newInstance(kind, size); } public static void main(String[] args) { ArrayMaker<String> stringMaker = new ArrayMaker<String>(String.class); String[] stringArray = stringMaker.create(9); System.out.println(Arrays.toString(stringArray)); } } /* Output: [null, null, null, null, null, null, null, null, null] *///:~
?????????Array.newInstance()??????
import java.util.*; public class ListMaker<T> { List<T> create() { //????<T>????,?????????????<T> return new ArrayList<T>(); } public static void main(String[] args) { ListMaker<String> stringMaker= new ListMaker<String>(); List<String> stringList = stringMaker.create(); } } ///:~
???list?????????????
import java.util.*; public class FilledListMaker<T> { List<T> create(T t, int n) { List<T> result = new ArrayList<T>(); for(int i = 0; i < n; i++) result.add(t); return result; } public static void main(String[] args) { FilledListMaker<String> stringMaker = new FilledListMaker<String>(); List<String> list = stringMaker.create("Hello", 4); System.out.println(list); } } /* Output: [Hello, Hello, Hello, Hello] *///:~
?????????????create()??T??????????????????????result??????T???????ArrayList< T >???????????????????????????????????????????????????
??????????????????????????????????????????
???????????????——???????????????????????????????????????????
15.8 ?????
??????????????????????????????????????????????
public class Erased<T> { private final int SIZE = 100; public static void f(Object arg) {//???????????? if(arg instanceof T) {} // Error T var = new T(); // Error new T???????????????????????????T??????? T[] array = new T[SIZE]; // Error T[] array = (T)new Object[100]; // Unchecked warning } } ///:~
???????????????????isInstance()?
class Building {} class House extends Building {} public class ClassTypeCapture<T> { Class<T> kind; public ClassTypeCapture(Class<T> kind) { this.kind = kind; } public boolean f(Object arg) { return kind.isInstance(arg); } public static void main(String[] args) { ClassTypeCapture<Building> ctt1 = new ClassTypeCapture<Building>(Building.class); System.out.println(ctt1.f(new Building())); System.out.println(ctt1.f(new House())); ClassTypeCapture<House> ctt2 = new ClassTypeCapture<House>(House.class); System.out.println(ctt2.f(new Building())); System.out.println(ctt2.f(new House())); } } /* Output: true true false true *///:~
15.8.1 ??????
?????????????????????
import static net.mindview.util.Print.*; class ClassAsFactory<T> { T x; public ClassAsFactory(Class<T> kind) { try { x = kind.newInstance(); } catch(Exception e) { throw new RuntimeException(e); } } } class Employee {} public class InstantiateGenericType { public static void main(String[] args) { ClassAsFactory<Employee> fe = new ClassAsFactory<Employee>(Employee.class); print("ClassAsFactory<Employee> succeeded"); try { ClassAsFactory<Integer> fi = new ClassAsFactory<Integer>(Integer.class);//???????Integer????????? } catch(Exception e) { print("ClassAsFactory<Integer> failed"); } } } /* Output: ClassAsFactory<Employee> succeeded ClassAsFactory<Integer> failed *///:~
??????????????
interface FactoryI<T> { T create(); } class Foo2<T> { private T x; public <F extends FactoryI<T>> Foo2(F factory) { x = factory.create(); } // ... } class IntegerFactory implements FactoryI<Integer> { public Integer create() { return new Integer(0); } } class Widget { public static class Factory implements FactoryI<Widget> { public Widget create() { return new Widget(); } } } public class FactoryConstraint { public static void main(String[] args) { new Foo2<Integer>(new IntegerFactory()); new Foo2<Widget>(new Widget.Factory()); } } ///:~
?????????
abstract class GenericWithCreate<T> { final T element; GenericWithCreate() { element = create(); } abstract T create(); } class X {} class Creator extends GenericWithCreate<X> { X create() { return new X(); } void f() { System.out.println(element.getClass().getSimpleName()); } } public class CreatorGeneric { public static void main(String[] args) { Creator c = new Creator(); c.f(); } } /* Output: X *///:~
15.8.2 ????
??????????????????????????????????ArrayList?
import java.util.*; public class ListOfGenerics<T> { private List<T> array = new ArrayList<T>(); public void add(T item) { array.add(item); } public T get(int index) { return array.get(index); } } ///:~
??????????????????
class Generic<T> {} public class ArrayOfGenericReference { static Generic<Integer>[] gia; } ///:~
??????????????????
????Object????????????????????????????????
public class ArrayOfGeneric { static final int SIZE = 100; static Generic<Integer>[] gia; @SuppressWarnings("unchecked") public static void main(String[] args) { // Compiles; produces ClassCastException: // gia = (Generic<Integer>[])new Object[SIZE]; //????? // Runtime type is the raw (erased) type: gia = (Generic<Integer>[])new Generic[SIZE]; System.out.println(gia.getClass().getSimpleName()); gia[0] = new Generic<Integer>(); //! gia[1] = new Object(); // Compile-time error // Discovers type mismatch at compile time: //! gia[2] = new Generic<Double>(); } } /* Output: Generic[] *///:~
???????????????????????????????????
public class GenericArray<T> { private T[] array; @SuppressWarnings("unchecked") public GenericArray(int sz) { array = (T[])new Object[sz]; }//??Object???T public void put(int index, T item) { array[index] = item; } public T get(int index) { return array[index]; } // Method that exposes the underlying representation: public T[] rep() { return array; } public static void main(String[] args) { GenericArray<Integer> gai = new GenericArray<Integer>(10); // This causes a ClassCastException: //! Integer[] ia = gai.rep(); // This is OK: Object[] oa = gai.rep(); } } ///:~
????T[] array=new T[sz]??????????????????????
???????????????????Object[]????????????T[]????????????????????????????????????????????????????Object[]??????????????????T????
public class GenericArray2<T> { private Object[] array; public GenericArray2(int sz) { array = new Object[sz]; } public void put(int index, T item) { array[index] = item; } @SuppressWarnings("unchecked") public T get(int index) { return (T)array[index]; } @SuppressWarnings("unchecked") public T[] rep() { return (T[])array; // Warning: unchecked cast } public static void main(String[] args) { GenericArray2<Integer> gai = new GenericArray2<Integer>(10); for(int i = 0; i < 10; i ++) gai.put(i, i); for(int i = 0; i < 10; i ++) System.out.print(gai.get(i) + " "); System.out.println(); try { Integer[] ia = gai.rep(); } catch(Exception e) { System.out.println(e); } } } /* Output: (Sample) 0 1 2 3 4 5 6 7 8 9 java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Integer; *///:~
????array??Object[]???T[]???????????????????????????????????
?????????????????
import java.lang.reflect.*; public class GenericArrayWithTypeToken<T> { private T[] array; @SuppressWarnings("unchecked") public GenericArrayWithTypeToken(Class<T> type, int sz) { array = (T[])Array.newInstance(type, sz); } public void put(int index, T item) { array[index] = item; } public T get(int index) { return array[index]; } // Expose the underlying representation: public T[] rep() { return array; } public static void main(String[] args) { GenericArrayWithTypeToken<Integer> gai = new GenericArrayWithTypeToken<Integer>( Integer.class, 10); // This now works: for(int i=0;i<10;i++) gai.put(i,i); Integer[] ia = gai.rep(); for (int i:ia ) System.out.println(i); } } ///:~
????Class< T >?????????????????????????????????????
15.9 ??
????????????????????????????????????????????????????????????????????????????????
?????????????????i???????????????????Object?????????????????????????????????????????????????????Java?????extends????
interface HasColor { java.awt.Color getColor(); } class Colored<T extends HasColor> { T item; Colored(T item) { this.item = item; } T getItem() { return item; } // The bound allows you to call a method: java.awt.Color color() { return item.getColor(); } } class Dimension { public int x, y, z; } // This won't work -- class must be first, then interfaces: // class ColoredDimension<T extends HasColor & Dimension> { // Multiple bounds: class ColoredDimension<T extends Dimension & HasColor> { T item; ColoredDimension(T item) { this.item = item; } T getItem() { return item; } java.awt.Color color() { return item.getColor(); } int getX() { return item.x; } int getY() { return item.y; } int getZ() { return item.z; } } interface Weight { int weight(); } // As with inheritance, you can have only one // concrete class but multiple interfaces: class Solid<T extends Dimension & HasColor & Weight> { T item; Solid(T item) { this.item = item; } T getItem() { return item; } java.awt.Color color() { return item.getColor(); } int getX() { return item.x; } int getY() { return item.y; } int getZ() { return item.z; } int weight() { return item.weight(); } } class Bounded extends Dimension implements HasColor, Weight { public java.awt.Color getColor() { return null; } public int weight() { return 0; } } public class BasicBounds { public static void main(String[] args) { Solid<Bounded> solid = new Solid<Bounded>(new Bounded()); solid.color(); solid.getY(); solid.weight(); } } ///:~
????????????
class HoldItem<T> { T item; HoldItem(T item) { this.item = item; } T getItem() { return item; } } class Colored2<T extends HasColor> extends HoldItem<T> { Colored2(T item) { super(item); } java.awt.Color color() { return item.getColor(); } } class ColoredDimension2<T extends Dimension & HasColor> extends Colored2<T> { ColoredDimension2(T item) { super(item); } int getX() { return item.x; } int getY() { return item.y; } int getZ() { return item.z; } } class Solid2<T extends Dimension & HasColor & Weight> extends ColoredDimension2<T> { Solid2(T item) { super(item); } int weight() { return item.weight(); } } public class InheritBounds { public static void main(String[] args) { Solid2<Bounded> solid2 = new Solid2<Bounded>(new Bounded()); solid2.color(); solid2.getY(); solid2.weight(); } } ///:~
????????
// Demonstrating bounds in Java generics. import java.util.*; interface SuperPower {} interface XRayVision extends SuperPower { void seeThroughWalls(); } interface SuperHearing extends SuperPower { void hearSubtleNoises(); } interface SuperSmell extends SuperPower { void trackBySmell(); } class SuperHero<POWER extends SuperPower> { POWER power; SuperHero(POWER power) { this.power = power; } POWER getPower() { return power; } } class SuperSleuth<POWER extends XRayVision>//POWER?????XRayVision??? extends SuperHero<POWER> { SuperSleuth(POWER power) { super(power); } void see() { power.seeThroughWalls(); } } class CanineHero<POWER extends SuperHearing & SuperSmell> extends SuperHero<POWER> { CanineHero(POWER power) { super(power); } void hear() { power.hearSubtleNoises(); } void smell() { power.trackBySmell(); } } class SuperHearSmell implements SuperHearing, SuperSmell { public void hearSubtleNoises() {} public void trackBySmell() {} } class DogBoy extends CanineHero<SuperHearSmell> { DogBoy() { super(new SuperHearSmell()); } } public class EpicBattle { // Bounds in generic methods: static <POWER extends SuperHearing> void useSuperHearing(SuperHero<POWER> hero) { hero.getPower().hearSubtleNoises(); } static <POWER extends SuperHearing & SuperSmell> void superFind(SuperHero<POWER> hero) { hero.getPower().hearSubtleNoises(); hero.getPower().trackBySmell(); } public static void main(String[] args) { DogBoy dogBoy = new DogBoy(); useSuperHearing(dogBoy); superFind(dogBoy); // You can do this: List<? extends SuperHearing> audioBoys; // But you can't do this: // List<? extends SuperHearing & SuperSmell> dogBoys; } } ///:~
15.10 ???
?????????????????????
class Fruit {} class Apple extends Fruit {} class Jonathan extends Apple {} class Orange extends Fruit {} public class CovariantArrays { public static void main(String[] args) { Fruit[] fruit = new Apple[10]; fruit[0] = new Apple(); // OK fruit[1] = new Jonathan(); // OK // Runtime type is Apple[], not Fruit[] or Orange[]: try { // Compiler allows you to add Fruit: fruit[2] = new Fruit(); // ArrayStoreException ?????? } catch(Exception e) { System.out.println(e); } try { // Compiler allows you to add Oranges: fruit[3] = new Orange(); // ArrayStoreException } catch(Exception e) { System.out.println(e); } } } /* Output: java.lang.ArrayStoreException: Fruit java.lang.ArrayStoreException: Orange *///:~
???????????????????????
import java.util.*; public class NonCovariantGenerics { // Compile Error: incompatible types: List<Fruit> flist = new ArrayList<Apple>();//?????Apple???????Fruit?? } ///:~
???????????????????????????????????????????????????????
import java.util.*; public class GenericsAndCovariance { public static void main(String[] args) { // Wildcards allow covariance: List<? extends Fruit> flist = new ArrayList<Apple>();//??????????????????????????????????Object??????? // Compile Error: can't add any type of object: // flist.add(new Apple()); // flist.add(new Fruit()); // flist.add(new Object()); flist.add(null); // Legal but uninteresting // We know that it returns at least Fruit: Fruit f = flist.get(0); } } ///:~
15.10.1 ???????
import java.util.*; public class CompilerIntelligence { public static void main(String[] args) { List<? extends Fruit> flist = Arrays.asList(new Apple()); Apple a = (Apple)flist.get(0); // No warning flist.contains(new Apple()); // ?????Object flist.indexOf(new Apple()); // Argument is 'Object' //flist.add(new Apple());??Add??????? extends Fruit????????????????????????????? } } ///:~
add()???????????????????contains()?indexOf()???Object??????????????ArrayList<? extends Fruit>??add()???????? extends Fruit?
public 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' 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 } } /* Output: (Sample) java.lang.ClassCastException: Apple cannot be cast to Orange true *///:~
15.10.2 ??
????????????????????????????????????<? super MyClass>,????????<? super T>?
import java.util.*; public class SuperTypeWildcards { static void writeTo(List<? super Apple> apples) { apples.add(new Apple()); apples.add(new Jonathan()); // apples.add(new Fruit()); // Error } } ///:~
??????????????????????????
import java.util.*; public class GenericWriting { static <T> void writeExact(List<T > list, T item) { list.add(item); } static List<Apple> apples = new ArrayList<Apple>(); static List<Fruit> fruit = new ArrayList<Fruit>(); static void f1() { writeExact(apples, new Apple()); // writeExact(fruit, new Apple()); // Error: // Incompatible types: found Fruit, required Apple } static <T> void writeWithWildcard(List<? super T> list, T item) { list.add(item); } static void f2() { writeWithWildcard(apples, new Apple()); writeWithWildcard(fruit, new Apple()); } public static void main(String[] args) { f1(); f2(); } } ///:~
15.10.3 ?????
?????< ? >????????????????????????????????
import java.util.*; public class UnboundedWildcards1 { static List list1; static List<?> list2; static List<? extends Object> list3; static void assign1(List list) { list1 = list; list2 = list; // list3 = list; // Warning: unchecked conversion // Found: List, Required: List<? extends Object> } static void assign2(List<?> list) { list1 = list; list2 = list; list3 = list; } static void assign3(List<? extends Object> list) { list1 = list; list2 = list; list3 = list; } public static void main(String[] args) { assign1(new ArrayList()); assign2(new ArrayList()); // assign3(new ArrayList()); // Warning: // Unchecked conversion. Found: ArrayList // Required: List<? extends Object> assign1(new ArrayList<String>()); assign2(new ArrayList<String>()); assign3(new ArrayList<String>()); // Both forms are acceptable as List<?>: List<?> wildList = new ArrayList(); wildList = new ArrayList<String>(); assign1(wildList); assign2(wildList); assign3(wildList); } } ///:~
< ? >?????????????????????????Java?????????????????????????????????????????????????
import java.util.*; public class UnboundedWildcards2 { static Map map1; static Map<?,?> map2; static Map<String,?> map3; static void assign1(Map map) { map1 = map; } static void assign2(Map<?,?> map) { map2 = map; } static void assign3(Map<String,?> map) { map3 = map; } public static void main(String[] args) { assign1(new HashMap()); assign2(new HashMap()); assign3(new HashMap()); // Warning: // Unchecked conversion. Found: HashMap // Required: Map<String,?> assign1(new HashMap<String,Integer>()); assign2(new HashMap<String,Integer>()); assign3(new HashMap<String,Integer>()); } } ///:~
????????????????????????LIst<?>??????LIst< Object >??List?????List< Object >——???????????List?????????Object?????List??List<?>??????????????List?
//: generics/Wildcards.java // Exploring the meaning of wildcards. public class Wildcards { // Raw argument: static void rawArgs(Holder holder, Object arg) { holder.set(arg); // Warning:?????Holder???????set??Object????? // Unchecked call to set(T) as a // member of the raw type Holder // holder.set(new Wildcards()); // Same warning // Can't do this; don't have any 'T': // T t = holder.get(); // OK, but type information has been lost: Object obj = holder.get(); } // Similar to rawArgs(), but errors instead of warnings: static void unboundedArg(Holder<?> holder, Object arg) { // holder.set(arg); // Error:????????????????Holder<?>???????????????????????????Object? // set(capture of ?) in Holder<capture of ?> // cannot be applied to (Object) // holder.set(new Wildcards()); // Same error // Can't do this; don't have any 'T': // T t = holder.get(); // OK, but type information has been lost: Object obj = holder.get(); } static <T> T exact1(Holder<T> holder) { T t = holder.get(); return 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.set(arg); // Error:????????????????????????? // set(capture of ? extends T) in // Holder<capture of ? extends T> // cannot be applied to (T) T t = holder.get(); return t; } static <T> void wildSupertype(Holder<? super T> holder, T arg) { holder.set(arg);//????????T????????? // T t = holder.get(); // Error: // Incompatible types: found Object, required T // OK, but type information has been lost: Object obj = holder.get();//??????????????????????Object?????? } public static void main(String[] args) { Holder raw = new Holder<Long>(); // Or: raw = new Holder(); Holder<Long> qualified = new Holder<Long>(); Holder<?> unbounded = new Holder<Long>(); Holder<? extends Long> bounded = new Holder<Long>(); Long lng = 1L; rawArgs(raw, lng); rawArgs(qualified, lng); rawArgs(unbounded, lng); rawArgs(bounded, lng); unboundedArg(raw, lng); unboundedArg(qualified, lng); unboundedArg(unbounded, lng); unboundedArg(bounded, lng); Object r1 = exact1(raw); // Warnings: // Unchecked conversion from Holder to Holder<T> // Unchecked method invocation: exact1(Holder<T>) // is applied to (Holder) Long r2 = exact1(qualified); Object r3 = exact1(unbounded); // Must return Object Long r4 = exact1(bounded); Long r5 = exact2(raw, lng); // Warnings: // Unchecked conversion from Holder to Holder<Long> // Unchecked method invocation: exact2(Holder<T>,T) // is applied to (Holder,Long) Long r6 = exact2(qualified, lng); // Long r7 = exact2(unbounded, lng); // Error: // exact2(Holder<T>,T) cannot be applied to // (Holder<capture of ?>,Long) // Long r8 = exact2(bounded, lng); // Error: // exact2(Holder<T>,T) cannot be applied // to (Holder<capture of ? extends Long>,Long) // Long r9 = wildSubtype(raw, lng); // Warnings: // Unchecked conversion from Holder // to Holder<? extends Long> // Unchecked method invocation: // wildSubtype(Holder<? extends T>,T) is // applied to (Holder,Long) Long r10 = wildSubtype(qualified, lng); // OK, but can only return Object: Object r11 = wildSubtype(unbounded, lng); Long r12 = wildSubtype(bounded, lng); // wildSupertype(raw, lng); // Warnings: // Unchecked conversion from Holder // to Holder<? super Long> // Unchecked method invocation: // wildSupertype(Holder<? super T>,T) // is applied to (Holder,Long) wildSupertype(qualified, lng); // wildSupertype(unbounded, lng); // Error: // wildSupertype(Holder<? super T>,T) cannot be // applied to (Holder<capture of ?>,Long) // wildSupertype(bounded, lng); // Error: // wildSupertype(Holder<? super T>,T) cannot be // applied to (Holder<capture of ? extends Long>,Long) } } ///:~
??????????????????????????????????????????????????????????????
15.10.4 ????
???????????<?>???????????????<?>????????????????????????????????????????????????????????????????????????????????????????????
public class CaptureConversion { static <T> void f1(Holder<T> holder) {//????????????? T t = holder.get(); System.out.println(t.getClass().getSimpleName()); } static void f2(Holder<?> holder) {//????????????????????f1.?????????f2???????????????f1???????? f1(holder); // Call with captured type } @SuppressWarnings("unchecked") public static void main(String[] args) { Holder raw = new Holder<Integer>(1); f1(raw); // Produces warnings f2(raw); // No warnings Holder rawBasic = new Holder(); rawBasic.set(new Object()); // Warning f2(rawBasic); // No warnings // Upcast to Holder<?>, still figures it out: Holder<?> wildcarded = new Holder<Double>(1.0); f2(wildcarded); } } /* Output: Integer Object Double *///:~
15.11 ??
15.11.1 ???????????????
???????????
import java.util.*; public class ListOfInt { public static void main(String[] args) { List<Integer> li = new ArrayList<Integer>(); for(int i = 0; i < 5; i++) li.add(i); for(int i : li) System.out.print(i + " "); } } /* Output: 0 1 2 3 4 *///:~
????????????????????????????Org.apache.commons.collections.primitives?
?????????Byte?Set?
import java.util.*; public class ByteSet { Byte[] possibles = { 1,2,3,4,5,6,7,8,9 }; Set<Byte> mySet = new HashSet<Byte>(Arrays.asList(possibles)); // But you can't do this: // Set<Byte> mySet2 = new HashSet<Byte>( // Arrays.<Byte>asList(1,2,3,4,5,6,7,8,9)); } ///:~
????Generator???
import net.mindview.util.*; // Fill an array using a generator: class FArray { public static <T> T[] fill(T[] a, Generator<T> gen) { for(int i = 0; i < a.length; i++) a[i] = gen.next(); return a; } } public class PrimitiveGenericTest { public static void main(String[] args) { String[] strings = FArray.fill( new String[8], new RandomGenerator.String()); for(String s : strings) System.out.println(s); Integer[] integers = FArray.fill( new Integer[7], new RandomGenerator.Integer()); for(int i: integers) System.out.println(i); // Autoboxing won't save you here. This won't compile: // int[] b = // FArray.fill(new int[7], new RandIntGenerator()); } } /* Output: YNzbrnyGcF OWZnTcQrGs eGZMmJMRoE suEcUOneOE dLsmwHLGEa hKcxrEqUCB bkInaMesbt 7052 6665 2654 3909 5202 2209 5458 *///:~
15.11.2 ???????
??????????????????????????????????????????
interface Payable<T> {} class Employee1 implements Payable<Employee1> {} class Hourly extends Employee implements Payable<Hourly> {} ///:~???????Object public class MultipleInterfaceVariants{ public static void main(String[] args){ } }
15.11.3 ?????
??????????????instanceof????????
???????????????Object???????????????????T?
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]; }//???????????????????????????pop()??????????????? } public class GenericCast { 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); for(int i = 0; i < SIZE; i++) { String s = strings.pop(); System.out.print(s + " "); } } } /* Output: J I H G F E D C B A *///:~
????????????????????????????????????
import java.io.*; import java.util.*; public class NeedCasting { @SuppressWarnings("unchecked") public static void main(String[] args) throws Exception { ObjectInputStream in = new ObjectInputStream( new FileInputStream("")); List<Widget> shapes = (List<Widget>)in.readObject();//readObject???????????????????????????? } } ///:~
???????
import java.io.*; import java.util.*; public class ClassCasting { @SuppressWarnings("unchecked") public void f(String[] args) throws Exception { ObjectInputStream in = new ObjectInputStream( new FileInputStream(args[0])); // Won't Compile: // List<Widget> lw1 = // List<Widget>.class.cast(in.readObject()); List<Widget> lw2 = List.class.cast(in.readObject()); } } ///:~
15.11.4 ??
??????????
import java.util.*; public class UseList<W,T> { void f1(List<T> v) {}//???????????? void f1(List<W> v) {} } ///:~
15.11.5 ???????
?????????????
public class ComparablePet implements Comparable<ComparablePet> { public int compareTo(ComparablePet arg) { return 0; } } ///:~
?????????????????????
class Cat extends ComparablePet implements Comparable<Cat>{ // Error: Comparable cannot be inherited with // different arguments: <Cat> and <Pet> public int compareTo(Cat arg) { return 0; } } ///:~
???????????????????????
class Hamster extends ComparablePet implements Comparable<ComparablePet> { public int compareTo(ComparablePet arg) { return 0; } } // Or just: class Gecko extends ComparablePet { public int compareTo(ComparablePet arg) { return 0; } } ///:~
15.12 ??????
?Java????????????????????
class SelfBounded<T extends SelfBounded<T>>
????????????????????????????SelfBounded???????T??T?????????????????T?????SelfBounded?
15.12.1 ???????
???????????????????????????????????????
class GenericType<T> {} public class CuriouslyRecurringGeneric extends GenericType<CuriouslyRecurringGeneric> {} ///:~
????????????
Java????????????????????????????????????????????????????????????????Object????
public class BasicHolder<T> { T element; void set(T arg) { element = arg; } T get() { return element; } void f() { System.out.println(element.getClass().getSimpleName()); } } ///:~
?????????????????????????????
class Subtype extends BasicHolder<Subtype> {} public class CRGWithBasicHolder { public static void main(String[] args) { Subtype st1 = new Subtype(), st2 = new Subtype(); st1.set(st2); Subtype st3 = st1.get(); st1.f(); } } /* Output: Subtype *///:~
CRG??????????????
?????????????????????
15.12.2 ???
BasicHolder????????????????
class Other {} class BasicOther extends BasicHolder<Other> {} public class Unconstrained { public static void main(String[] args) { BasicOther b = new BasicOther(), b2 = new BasicOther(); b.set(new Other()); Other other = b.get(); b.f(); } } /* Output: Other *///:~
??????????????????????????????
class SelfBounded<T extends SelfBounded<T>> { T element; SelfBounded<T> set(T arg) { element = arg; return this; } T get() {System.out.println(this.getClass().getSimpleName()); return element; } } class A extends SelfBounded<A> {}//????????????????????? class B extends SelfBounded<A> {} // Also OK class C extends SelfBounded<C> { C setAndGet(C arg) { set(arg); return get(); } } class D {} // Can't do this: //class E extends SelfBounded<D> {} // Compile error: Type parameter D is not within its bound // Alas, you can do this, so you can't force the idiom: class F extends SelfBounded {}//?????????????? public class SelfBounding { public static void main(String[] args) { A a = new A(); a.set(new A()); a = a.set(new A()).get(); a = a.get(); C c = new C(); c = c.setAndGet(new C()); } } ///:~
??????????????????????????????
???????????????????????????
public class NotSelfBounded<T> { T element; NotSelfBounded<T> set(T arg) { element = arg; return this; } T get() { return element; } } class A2 extends NotSelfBounded<A2> {} class B2 extends NotSelfBounded<A2> {} class C2 extends NotSelfBounded<C2> { C2 setAndGet(C2 arg) { set(arg); return get(); } } class D2 {} // Now this is OK: class E2 extends NotSelfBounded<D2> {} ///:~
???????????????????????????????????????????????????????????????
??????????????
public class SelfBoundingMethods { static <T extends SelfBounded<T>> T f(T arg) { return arg.set(arg).get(); } public static void main(String[] args) { A a = f(new A()); } } ///:~
15.12.3 ????
??????????????????????——??????????????
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(); } public class CovariantReturnTypes { void test(DerivedGetter d) { Derived d2 = d.get(); } } ///:~
?????????????????????????
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 } } ///:~
???????????????????????????????????????????
interface SelfBoundSetter<T extends SelfBoundSetter<T>> { void set(T arg); } interface Setter extends SelfBoundSetter<Setter> {} public class SelfBoundingAndCovariantArguments { void testA(Setter s1, Setter s2, SelfBoundSetter sbs) { s1.set(s2); // s1.set(sbs); // Error:??????????????????set()?????????????????????????????????? // set(Setter) in SelfBoundSetter<Setter> // cannot be applied to (SelfBoundSetter) } } ///:~
??????????????????????????????
class GenericSetter<T> { // Not self-bounded void set(T arg){ System.out.println("GenericSetter.set(Base)"); } } class DerivedGS extends GenericSetter<Base> { void set(Derived derived){ System.out.println("DerivedGS.set(Derived)"); } } public class PlainGenericInheritance { public static void main(String[] args) { Base base = new Base(); Derived derived = new Derived(); DerivedGS dgs = new DerivedGS(); dgs.set(derived); dgs.set(base); // Compiles: overloaded, not overridden! } } /* Output: DerivedGS.set(Derived) GenericSetter.set(Base) *///:~
???????????????????????????????????????????????????
15.13 ??????
Java SE5?java.util.Collections?????????????????checkedCollection()?checkedList(),checkedMap(),checkedSet(),checkedSortedMap()?checkedSortedSet()????????????????????????????????????????????????????
import pets.*; import java.util.*; public class CheckedList { @SuppressWarnings("unchecked") static void oldStyleMethod(List probablyDogs) { probablyDogs.add(new Cat()); } public static void main(String[] args) { List<Dog> dogs1 = new ArrayList<Dog>(); oldStyleMethod(dogs1); // Quietly accepts a Cat List<Dog> dogs2 = Collections.checkedList( new ArrayList<Dog>(), Dog.class); try { oldStyleMethod(dogs2); // Throws an exception????? } catch(Exception e) { System.out.println(e); } // Derived types work fine: List<Pet> pets = Collections.checkedList(//?????????????????? new ArrayList<Pet>(), Pet.class); pets.add(new Dog()); pets.add(new Cat()); } } /* Output: java.lang.ClassCastException: Attempt to insert class typeinfo.pets.Cat element into collection with element type class typeinfo.pets.Dog *///:~
15.14 ??
???????????????????????catch??????????????????????????????????????????????????Throwable?
import java.util.*; interface Processor<T,E extends Exception> { void process(List<T> resultCollector) throws E; } class ProcessRunner<T,E extends Exception> extends ArrayList<Processor<T,E>> { List<T> processAll() throws E { List<T> resultCollector = new ArrayList<T>(); for(Processor<T,E> processor : this) processor.process(resultCollector); return resultCollector; } } class Failure1 extends Exception {} class Processor1 implements Processor<String,Failure1> { static int count = 3; public void process(List<String> resultCollector) throws Failure1 { if(count-- > 1) resultCollector.add("Hep!"); else resultCollector.add("Ho!"); if(count < 0) throw new Failure1(); } } class Failure2 extends Exception {} class Processor2 implements Processor<Integer,Failure2> { static int count = 2; public void process(List<Integer> resultCollector) throws Failure2 { if(count-- == 0) resultCollector.add(47); else { resultCollector.add(11); } if(count < 0) throw new Failure2(); } } public class ThrowGenericException { public static void main(String[] args) { ProcessRunner<String,Failure1> runner = new ProcessRunner<String,Failure1>(); for(int i = 0; i < 3; i++) runner.add(new Processor1()); try { System.out.println(runner.processAll()); } catch(Failure1 e) { System.out.println(e); } ProcessRunner<Integer,Failure2> runner2 = new ProcessRunner<Integer,Failure2>(); for(int i = 0; i < 3; i++) runner2.add(new Processor2()); try { System.out.println(runner2.processAll()); } catch(Failure2 e) { System.out.println(e); } } } ///:~
15.15 ??
?????????????????????????????????
????????????????????????????????????????????????????????????????????????????
15.15.2 ?????
import java.util.*; 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 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 {//???????????????Mixin????????????Mixin?????????????????????? private TimeStamped timeStamp = new TimeStampedImp(); private SerialNumbered serialNumber = new SerialNumberedImp(); public long getStamp() { return timeStamp.getStamp(); } public long getSerialNumber() { return serialNumber.getSerialNumber(); } } public class Mixins { 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()); System.out.println(mixin2.get() + " " + mixin2.getStamp() + " " + mixin2.getSerialNumber()); } } /* Output: (Sample) test string 1 1132437151359 1 test string 2 1132437151359 2 *///:~
15.15.3 ???????
?????????????????????????????????????????????????????????????????????
??????????????????????????????????????????????????????????????????????????????????????????????????
???????????????????????????????
???????????????
package decorator; import java.util.*; class Basic { private String value; public void set(String val) { value = val; } public String get() { return value; } } class Decorator extends Basic { protected Basic basic; public Decorator(Basic basic) { this.basic = basic; } public void set(String val) { basic.set(val); } public String get() { return basic.get(); } } class TimeStamped extends Decorator { private final long timeStamp; public TimeStamped(Basic basic) { super(basic); timeStamp = new Date().getTime(); } public long getStamp() { return timeStamp; } } class SerialNumbered extends Decorator { private static long counter = 1; private final long serialNumber = counter++; public SerialNumbered(Basic basic) { super(basic); } public long getSerialNumber() { return serialNumber; } } public class Decoration { public static void main(String[] args) { TimeStamped t = new TimeStamped(new Basic()); TimeStamped t2 = new TimeStamped( new SerialNumbered(new Basic())); //! t2.getSerialNumber(); // Not available SerialNumbered s = new SerialNumbered(new Basic()); SerialNumbered s2 = new SerialNumbered( new TimeStamped(new Basic())); //! s2.getStamp(); // Not available } } ///:~
??????????????????????????????????????????????????????????????????????????????????????
15.15.4 ???????
????????????????????????????????????????????????????????????
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)); } } public class DynamicProxyMixin { public static void main(String[] args) { Object mixin = MixinProxy.newInstance( tuple(new BasicImp(), Basic.class), tuple(new TimeStampedImp(), TimeStamped.class), tuple(new SerialNumberedImp(),SerialNumbered.class)); Basic b = (Basic)mixin; TimeStamped t = (TimeStamped)mixin; SerialNumbered s = (SerialNumbered)mixin; b.set("Hello"); System.out.println(b.get()); System.out.println(t.getStamp()); System.out.println(s.getSerialNumber()); } } /* Output: (Sample) Hello 1132519137015 1 *///:~
15.16 ??????
?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????
????????????????????????????????
?????????????????????????????????????????????????????????????????speak()?sit()?????????????????????????
???????????????
????????????????
15.17 ????????????
??Java?????????????????????????????????????????
15.17.1 ??
?????????????
//: generics/LatentReflection.java // Using Reflection to produce latent typing. import java.lang.reflect.*; import static net.mindview.util.Print.*; // Does not implement Performs: class Mime { public void walkAgainstTheWind() {} public void sit() { print("Pretending to sit"); } public void pushInvisibleWalls() {} public String toString() { return "Mime"; } } // Does not implement Performs: class SmartDog { public void speak() { print("Woof!"); } public void sit() { print("Sitting"); } public void reproduce() {} } class CommunicateReflectively { public static void perform(Object speaker) { Class<?> spkr = speaker.getClass(); try { try { Method speak = spkr.getMethod("speak"); speak.invoke(speaker); } catch(NoSuchMethodException e) { print(speaker + " cannot speak"); } try { Method sit = spkr.getMethod("sit"); sit.invoke(speaker); } catch(NoSuchMethodException e) { print(speaker + " cannot sit"); } } catch(Exception e) { throw new RuntimeException(speaker.toString(), e); } } } public class LatentReflection { public static void main(String[] args) { CommunicateReflectively.perform(new SmartDog()); CommunicateReflectively.perform(new Robot()); CommunicateReflectively.perform(new Mime()); } } /* Output: Woof! Sitting Click! Clank! Mime cannot speak Pretending to sit *///:~
????????????????????????????????????????????????
15.17.2 ??????????
??????????
import java.lang.reflect.*; import java.util.*; import static net.mindview.util.Print.*; public 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); } } } class ApplyTest { 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")); SimpleQueue<Shape> shapeQ = new SimpleQueue<Shape>(); for(int i = 0; i < 5; i++) { shapeQ.add(new Shape()); shapeQ.add(new Square()); } Apply.apply(shapeQ, Shape.class.getMethod("rotate")); } } /* (Execute to see output) *///:~
apple(0??????????Iterable????????List?????Collection??
????????
import java.util.*; public 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(); } } ///:~
15.17.3 ????????????
??Iterable?????????????????????????????????
import java.util.*; // Doesn't work with "anything that has an add()." There is // no "Addable" interface so we are narrowed to using a // Collection. We cannot generalize using generics in // this case. public class Fill { public static <T> void fill(Collection<T> collection, Class<? extends T> classToken, int size) { for(int i = 0; i < size; i++) // Assumes default constructor: try { collection.add(classToken.newInstance()); } catch(Exception e) { throw new RuntimeException(e); } } } class Contract { private static long counter = 0; private final long id = counter++; public String toString() { return getClass().getName() + " " + id; } } class TitleTransfer extends Contract {} class FillTest { public static void main(String[] args) { List<Contract> contracts = new ArrayList<Contract>(); Fill.fill(contracts, Contract.class, 3); Fill.fill(contracts, TitleTransfer.class, 2); for(Contract c: contracts) System.out.println(c); SimpleQueue<Contract> contractQueue = new SimpleQueue<Contract>(); // Won't work. fill() is not generic enough: // Fill.fill(contractQueue, Contract.class, 3); } } /* Output: Contract 0 Contract 1 Contract 2 TitleTransfer 3 TitleTransfer 4 *///:~
15.17.4 ????????????
????????????????????????????????????????????????????????????????????????????????????????????????????????????????
??????????????????????????
import coffee.*; import java.util.*; import net.mindview.util.*; import static net.mindview.util.Print.*; interface Addable<T> { void add(T t); } public 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); } } class Fill2Test { public static void main(String[] args) { // Adapt a Collection: List<Coffee> carrier = new ArrayList<Coffee>(); Fill2.fill( new AddableCollectionAdapter<Coffee>(carrier), Coffee.class, 3); // Helper method captures the type: Fill2.fill(Adapter.collectionAdapter(carrier), Latte.class, 2); for(Coffee c: carrier) print(c); print("----------------------"); // Use an adapted class: AddableSimpleQueue<Coffee> coffeeQueue = new AddableSimpleQueue<Coffee>(); Fill2.fill(coffeeQueue, Mocha.class, 4); Fill2.fill(coffeeQueue, Latte.class, 1); for(Coffee c: coffeeQueue) print(c); } } /* Output: Coffee 0 Coffee 1 Coffee 2 Latte 3 Latte 4 ---------------------- Mocha 5 Mocha 6 Mocha 7 Mocha 8 Latte 9 *///:~
15.18 ?????????
??????????????????????????????????????????????
?????????????????????????????????????????????????
???????????????????????????????????????????????????????
//: generics/Functional.java 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); } public class Functional { // 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())); } } /* Output: 28 -26 [5, 6, 7] 5040 210 11.000000 [3.300000, 4.400000] [11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47] 311 true 265 [0.000001, 0.000001, 0.000001, 0.000001] *///:~