标签:
通过几个例子来表现java泛型的特性:泛型出现的最主要目的是能跨多个类工作,如果没有这个目的,不如使用具体类型
1、可重用性:持有对象,泛型的目的之一就是制定容器持有什么类型的对象,而且由编译器保证类型的正确性
public class Holder<T> { private T a; public Holder(T a){this.a = a;} public T getA() {return a;} public void setA(T a) {this.a = a;} public static void main(String[] args) { Holder<Automobile> h = new Holder<Automobile>(new Automobile()); Automobile a = h.getA(); a.f(); } }
2、元组:持有多个对象
public class TwoTuple<A, B> { public final A first; public final B second; public TwoTuple(A a,B b){ first = a; second = b; } @Override public String toString() { return "("+first+", "+second+")"; } } public class ThreeTuple<A, B, C> extends TwoTuple<A, B> { public final C third; public ThreeTuple(A a, B b,C c) { super(a, b); third = c; } @Override public String toString() { return "("+first+", "+second+", "+third+")"; } } public class FourTuple<A, B, C, D> extends ThreeTuple<A, B, C> { public final D fourth; public FourTuple(A a, B b, C c,D d) { super(a, b, c); fourth = d; } @Override public String toString() { return "("+first+", "+second+", "+third+", "+fourth+")"; } } public class FiveTuple<A, B, C, D, E> extends FourTuple<A, B, C, D> { public final E fifth; public FiveTuple(A a, B b, C c, D d,E e) { super(a, b, c, d); fifth = e; } @Override public String toString() { return "("+first+", "+second+", "+third+", "+fourth+", "+fifth+")"; } }使用:
public class Amphibian {} public class Vehicle {} public class TupleTest { static TwoTuple<String,Integer> f(){ 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<Amphibian, String, Integer, Double> h(){ return new FourTuple<Amphibian, String, Integer, Double>( new Amphibian(), "hi", 47, 11.1); } 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); System.out.println(g()); System.out.println(h()); System.out.println(k()); } } //(hi, 47) //(test01.Amphibian@7afa0094, hi, 47) //(test01.Amphibian@2d8eef25, hi, 47, 11.1) //(test01.Vehicle@233aa44, test01.Amphibian@def577d, hi, 47, 11.1)
这里没有使用get、set方法,因为final本来就能保证他是安全的
简化:目的在于简化为一个工具类,后面我们可以看到在使用过程中能减少一部分代码并增加可读性:
public class Tuple { public static <A,B> TwoTuple<A, B> tuple(A a,B b){ return new TwoTuple<A, B>(a, b); } public static <A,B,C> ThreeTuple<A, B, C> tuple(A a,B b,C c){ return new ThreeTuple<A, B, C>(a, b, c); } public static<A,B,C,D> FourTuple<A,B,C,D> tuple(A a,B b, C c,D d){ return new FourTuple<A, B, C, D>(a, b, c, d); } public static <A,B,C,D,E> FiveTuple<A,B,C,D,E> tuple(A a,B b,C c,D d,E e){ return new FiveTuple<A, B, C, D, E>(a, b, c, d, e); } } public class TupleTest2 { static TwoTuple<String,Integer> f(){ return Tuple.tuple("hi",47); } static TwoTuple f2(){return Tuple.tuple("hi",47);} static ThreeTuple<Amphibian, String, Integer> g(){ return Tuple.tuple(new Amphibian(), "hi", 47); } static FourTuple<Amphibian, String, Integer, Double> h(){ return Tuple.tuple(new Amphibian(), "hi", 47, 11.1); } static FiveTuple<Vehicle, Amphibian, String, Integer, Double> k(){ return Tuple.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()); } }
3、通用堆栈类与末端哨兵:
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>(); public void push(T item){ top = new Node<T>(item, top);//第一次push的时候最底层是item=null,next=null } 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:"Phaser on stun!".split(" "))lss.push(s); String s; //最后的节点top和next都是null,跳出循环 while((s=lss.pop())!=null)System.out.println(s); } } //stun! //on //Phaser
4、实现一个返回随机类型的list,当然类型那个由你去指定
//利用randomList处理不同的元素 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 for jumped over " +"the lazy brown dog").split(" ")) rs.add(s); for(int i = 0;i<11;i++) System.out.println(rs.select()+" "); } }
生成器接口和实体类
public interface Generator<T> { T next(); } public class Coffee { private static long counter = 0; private final long id = counter++; @Override public String toString() { return getClass().getSimpleName()+" "+id; } } public class Latte extends Coffee {} public class Americano extends Coffee {} public class Breve extends Coffee {} public class Cappuccino extends Coffee {} public class Mocha extends Coffee {}使用:他创造对象的方式是随机的,如果你需要的不是随机的对象当然需要额外的条件,即使java编程思想里面说“他不需额外的信息”,毕竟不存在不干活就收获的方法
public class CoffeeGenerator implements Generator<Coffee>, Iterable<Coffee> { private Class[] types = {Latte.class,Mocha.class,Cappuccino.class, Americano.class,Breve.class}; private static Random rand = new Random(47); public CoffeeGenerator(){} private int size = 0; public CoffeeGenerator(int sz){size = sz;} @Override public Iterator<Coffee> iterator() { return new CoffeeIterator(); } @Override public Coffee next() { try {return (Coffee)types[rand.nextInt( types.length)].newInstance(); } catch (Exception e) { throw new RuntimeException(e); } } class CoffeeIterator implements Iterator<Coffee>{ int count = size; @Override public boolean hasNext() { return count>0; } @Override public Coffee next() { count--; return CoffeeGenerator.this.next(); } @Override public void remove() { throw new UnsupportedOperationException(); } } public static void main(String[] args) { CoffeeGenerator gen = new CoffeeGenerator(); for(int i=0;i<5;i++){ System.out.println(gen.next()); } //这里默认会使用Iterator for(Coffee c:new CoffeeGenerator(5)){ System.out.println(c); } } } //Americano 0 //Latte 1 //Americano 2 //Mocha 3 //Mocha 4 //Breve 5 //Americano 6 //Latte 7 //Cappuccino 8 //Cappuccino 9
如果仅仅是通过定义接口的方法去定义生成器,这往往是不够的,利用类型信息,我们可以更进一步:
//一个通用的Generator public class BasicGenerator<T> implements Generator<T>{ private Class<T> type; public BasicGenerator(Class<T> type){this.type = type;} @Override public T next() { try { return type.newInstance(); } catch (Exception e) { throw new RuntimeException(e); } } public static<T> Generator<T> create(Class<T> type){ return new BasicGenerator<T>(type); } }使用:
public class CountedObject { private static long counter = 0; private final long id = counter++; public long id(){return id;} public String toString() {return "CountedObject "+id;}; 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()); } }
甚至我们可以利用生成器其填充一个集合:
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; } }
6、生成器的另一个例子:生成fibonacci数列
public class Fibonacci implements Generator<Integer> { private int count = 0; public int fib(int n){ if(n<2)return 1; return fib(n-2)+fib(n-1); } @Override public Integer next() { return fib(count++); } public static void main(String[] args) { Fibonacci gen = new Fibonacci(); for(int i = 0;i<18;i++){ System.out.print(gen.next()+" "); //1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 } } }当然也可以通过适配器:
public class IterableFibnoacci extends Fibonacci implements Iterable<Integer> { private int n; public IterableFibnoacci(int count){n = count;} @Override public Iterator<Integer> iterator() { return new Iterator<Integer>() { @Override public void remove() { throw new UnsupportedOperationException(); } @Override public Integer next() { n--; return IterableFibnoacci.this.next(); } @Override public boolean hasNext() {return n>0;} }; } public static void main(String[] args) { for(int i:new IterableFibnoacci(18)){ System.out.print(i+" "); } //1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 } }
//一个能节省代码的容器创造类 public class New { 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>(); } public static void main(String[] args) { Map<String, List<String>> sls = New.map(); //相比这种形式能节省很多代码 //Map<String,List<? extends String>> sample = new HashMap<String, List<? extends String>>(); //如果要调用一个泛型方法f(New.<Person,List<Pet>>map()) List<String> ls = New.list(); LinkedList<String> lls = New.lList(); Set<String> ss = New.set(); Queue<String> qs = New.queue(); } }
8、Set集合工具:实现对象的交集等操作
public class Sets { //把两个参数合并在一起 public static <T> Set<T> union(Set<T> a,Set<T> b){ Set<T> result = new HashSet<T>(a); result.addAll(b); return result; } //返回交集 public static <T> Set<T> intersection(Set<T> a,Set<T> b){ Set<T> result = new HashSet<T>(a); result.retainAll(b); return result; } //移除元素 public static <T> Set<T> difference(Set<T> superset,Set<T> subset){ Set<T> result = new HashSet<T>(superset); result.removeAll(subset); return result; } //返回交集之外的所有元素 public static <T> Set<T> complement(Set<T> a,Set<T> b){ return difference(union(a, b), intersection(a, b)); } }
9、泛型与匿名内部类
public class Customer { private static long counter = 1; private final long id = counter++; private Customer(){} @Override public String toString() { return "Customer "+id; } public static Generator<Customer> generator(){ return new Generator<Customer>() { @Override public Customer next() { return new Customer(); } }; } } public class Teller { private static long counter = 1; private final long id = counter++; private Teller(){} @Override public String toString() { return "Teller "+id; } public static Generator<Teller> generator = new Generator<Teller>() { @Override public Teller next() { return new Teller(); } }; }方法
public class BankTeller { public static void serve(Teller t,Customer c){ System.out.println(t+" serve "+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); } } } //Teller 3 serve Customer 1 //Teller 2 serve Customer 2 //Teller 3 serve Customer 3 //Teller 1 serve Customer 4 //Teller 1 serve Customer 5 //Teller 3 serve Customer 6 //Teller 1 serve Customer 7 //Teller 2 serve Customer 8 //Teller 3 serve Customer 9 //Teller 3 serve Customer 10 //Teller 2 serve Customer 11 //Teller 4 serve Customer 12 //Teller 2 serve Customer 13 //Teller 1 serve Customer 14 //Teller 1 serve Customer 1510、构建复杂模型的例子:比如一个商店里面有多个集合:走廊包括货架,货架包括商品,这就存在一种嵌套关系:
public class Product { private final int id; private String description; private double price; public Product(int id, String description, double price) { this.id = id; this.description = description; this.price = price; System.out.println(toString()); } @Override 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); @Override public Product next() { return new Product(rand.nextInt(1000),"Test", Math.round(rand.nextDouble()*1000.0+0.99)); } }; } public 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)); } } } public class Store extends ArrayList<Aisle> { public Store(int nAisles,int nShelves,int nProducts){ for(int i = 0;i<nAisles;i++){ add(new Aisle(nShelves, nProducts)); } } @Override 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) { //14条走廊,每条走廊5个货架,每个货架10个商品 System.out.println(new Store(14, 5, 10)); } } //258: Test.price: $401.0 //861: Test.price: $161.0 //868: Test.price: $418.0 //207: Test.price: $269.0 //551: Test.price: $115.0 //278: Test.price: $805.0 //当然还有更多....
11、泛型创建类型实例:利用newInstance并不是万金油,因为他必须需要一个默认构造器,当然不能是new T[]的方法
(1)、工厂方法:
public interface FactoryI<T> { T create(); } public class IntegerFactory implements FactoryI<Integer>{ @Override public Integer create() { return new Integer(0); } } public class Widget { public static class Factory implements FactoryI<Widget>{ @Override public Widget create() { return new Widget(); } } } public class Foo2<T> { private T x; public <F extends FactoryI<T>> Foo2(F factory){ x = factory.create(); } public T getX() { return x; } } public class FactoryConstraint { public static void main(String[] args) { Foo2<Integer> i =new Foo2<Integer>(new IntegerFactory()); System.out.println(i.getX()); new Foo2<Widget>(new Widget.Factory()); } }(2)、模版方法:
public abstract class GenericWithCreate<T> { final T element; public GenericWithCreate() { // TODO Auto-generated constructor stub element = create(); } abstract T create(); } public class X { } public class Creator extends GenericWithCreate<X> { @Override 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(); } }
12、擦除动机:使得泛化的客户端可以用非泛化的类库来使用,反之亦然(迁移兼容性)
“泛型是JDK1.5才出现的,所以为了兼容,采用了擦除的方式实现。泛型类型只有在静态类型检查期间才出现,在此之后,程序中所有泛型类型都被擦除,替换为他们的非泛型上界。例如List<T>将被擦除为List,而普通的类型变量在未指定边界的情况下将被擦除为Object。”
擦除可以是现有泛型客户端代码能够在不改变的情况下继续使用,直至客户端准备好用泛型重写这些代码,无论什么情况,我们都要在编写泛型代码是提醒自己:这只是一个Object,擦除方法或类的内部移除了有关实际类型的信息,编译器仍旧可以确保在方法或者类中使用类型内部的一致性
例如List<T>泛型在运行内部会进行擦除,但是运行之后能辨识的原因是RTTI(运行时类型判定)
比如:
public class Fnorkle {} public class Frob {} public class Particle<POSITION, MOMENTUM> {} public class Quark<Q> {} public class LostInformation { public static void main(String[] args) { List<Frob> list = new ArrayList<Frob>(); System.out.println(Arrays.toString(list.getClass().getTypeParameters())); Map<Frob,Fnorkle> map = new HashMap<Frob, Fnorkle>(); System.out.println(Arrays.toString(map.getClass().getTypeParameters())); Quark<Fnorkle> quark = new Quark<Fnorkle>(); System.out.println(Arrays.toString(quark.getClass().getTypeParameters())); Particle<Long, Double> p = new Particle<Long, Double>(); System.out.println(Arrays.toString(p.getClass().getTypeParameters())); } } //[E] //[K, V] //[Q] //[POSITION, MOMENTUM]又比如:
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); } }
我们会发现输出的是true
内部把具体类型擦除成Object,用这两个类去证明:
//public class SimpleHoder{ // private Object obj; // get\set方法 //}
//public class GenericHolder<T>{ // private T obj; // ... //}
以这两种方式去去持有一个类,而他们反编译的字节码基本是一样的,对进入set的类型检查是不需要的,因为这由编译器进行,而get返回值的转型仍然是需要的,在前者,他已经规定是Object,所以要转型,但是后者由于RTTI,不需要强转
重载:
public class UseList<W,T>{ void f(List<T> v){} void f(List<W> v){} }这两种方法签名是一样的
参考类型擦擦除文章:http://blog.csdn.net/caihaijiang/article/details/6403349#t3
在泛型内部,无法获得任何有关泛型参数类型的信息,而一致性,可以用下面这个例子体现:
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); } }
我们在看一个例子,这是在内部的擦除,当然这也是合情合理的:
public class HasF { public void f(){System.out.println("f()");} } public class Manipulator<T> { T obj; public Manipulator(T obj) {this.obj = obj;} public void manipulate(){//我们能看到在泛型代码内部,类型是被擦除的 //obj.f(); } public T getObj() { return obj; } } public class Manipulation { public static void main(String[] args) { HasF hf = new HasF(); Manipulator<HasF> man = new Manipulator<HasF>(hf); man.manipulate();//自然不能待用f() HasF anoHf = man.getObj();//但是这对我们目前为止学过的并没有冲突,因为在外部,编译器能运行时识别这是什么类 anoHf.f();//f() } }所以当我们使用instanceof的时候,很一般的想法:这当然是不可能的,因为擦除
public class Erased<T> { private final int SIZE = 100; public static void f(Object arg){ //无法编译 // if(arg instanceof T){} // T var = new T(); // T[] array = new T[SIZE]; } }但是却可以利用isInstance匹配类型参数
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())); } } //true //true //false //true
像Erased上面,我们不能通过这样的方式去创建一个对象,T var = new T()这种在第11个例子里面有替代方法
而数组,我们需要注意的是Integer跟Integer[]是不一样的对象,当我们关联到擦除
//持有array的list 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); } public List<T> rep(){ return array; } } public class Generic<T> { } public class ArrayOfGeneric { static final int SIZE = 100; static Generic<Integer>[] gia; @SuppressWarnings("unchecked") public static void main(String[] args) { //这里能获得数组的行为,他并没有形如T[]这样子的形式,所有放在List<T>里面 ListOfGenerics<Integer> ll = new ListOfGenerics<Integer>(); ll.add(1); ll.add(2); Integer i = ll.get(0); System.out.println(i); List<Integer> list = ll.rep(); System.out.println(list.get(0)+" "+list.get(1)); //ClassCastException //gia = (Generic<Integer>[]) new Object[SIZE]; gia = (Generic<Integer>[])new Generic[SIZE]; System.out.println(gia.getClass().getSimpleName());//Generic[] gia[0] = new Generic<Integer>(); System.out.println(gia[0]);//test17.Generic@30e79eb3 //很明显这不是Integer[]的对象,而是一个Generic数组对象,与List不一样 //编译错误 //gia[1] = new Object(); //gia[2] = new Generic<Double>(); } }
这是利用list来获取数组的行为,但是真正关联到数组呢?
我们看看另外几种持有数组的方式:
(1)、T[] array;
public class GenericArray<T> { private T[] array; @SuppressWarnings("unchecked") public GenericArray(int sz){array = (T[]) new Object[sz];} public void put(int index,T item){array[index] = item;} public T get(int index){return array[index];} public T[] rep(){return array;} public static void main(String[] args) { GenericArray<Integer> gai = new GenericArray<Integer>(10); Object[] oa = gai.rep(); System.out.println(oa.getClass().getSimpleName());//Object[] //除非是确切的类型,Integer而不是Integer[],泛型并不会识别 //Integer[] i = (Integer[])gai.rep();//ClassCastException //擦除:数组实际运行的是Object[] //这里能运行,这里很确切地告诉了你这是Integer gai.put(0, 1); Integer ii = gai.get(0); System.out.println(ii);//1 } }(2)、private Object[] array;
public class GenericArray2<T> { private Object[] array; @SuppressWarnings("unchecked") public GenericArray2(int sz){array = (T[]) 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;} 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(); //如果把返回类型改为Object[],同时在这里强转类型,结果仍然是异常 } catch (Exception e) { System.out.println(e); } //ClassCastException这里仍然会报 //把T[]当作OBJECT处理的优势 //我们不太可能忘记数组的运行时类型,从而意外的引入缺陷,尽管大多数也可能是所有这类缺陷都可以在运行时快速的探测到 } }除了上面用list来解决,这里存在一种解决方案
newInstance是推荐的创建数组方式
public class GenericArrayWithTypeToken<T> { private T[] array; @SuppressWarnings("unchecked") public GenericArrayWithTypeToken(Class<T> type,int sz) { //这种方式是使用Array.newInstance,程序能正常运行 array = (T[]) Array.newInstance(type, sz); } public void put(int index,T item){ array[index] = item; } public T get(int index){ return array[index]; } public T[] rep(){ return array; } public static void main(String[] args) { GenericArrayWithTypeToken<Integer> gai = new GenericArrayWithTypeToken<Integer>(Integer.class, 10); Integer[] ia = gai.rep(); } }
13、边界:对象进入和离开方法的起点,编译器在编译期执行类型检查并插入转型代码的地点,在泛型中的所有动作的发生在边界处——对传递进来的值进行额外的编译期检查,并插入对传递出去的值的转型。边界就是发生动作的地方,按照笔者通俗的理解,形如<? extends xxx>或者<? super XX>的可以理解为边界
比如:List<? extends Animal>表示Animal是这个类型的上界,他可能是List<Cat>、List<Dog>,除了知道他是一个包括Animal的以及Animal子类,具体类型是不知道的
public void testAdd(List<? extends Animal> list){ //....其他逻辑 list.add(new Animal("animal")); list.add(new Bird("bird")); list.add(new Cat("cat")); }他可能是List<Cat>、也可以是List<Dog>、也可以是List<Animal>,如果是List<Dog>,那么添加Animal自然是不合法的
所以:
不能往List<? extends Pet> 添加任意对象,除了null
他不能添加对象,因为无法知道具体类型,但是能运用在可以确定的方法调用中:
如果act中参数不是List<? extends Animal> list而是List<Animal> list,编译器并不能识别List<Cat>,因为List<Animal>的类型是确定的,即Animal,通过添加上界,辨识传进来的是Animal的子类,于是可以使用List<Cat>
public class AnimalTrainer { public void act(List<? extends Animal> list) { for (Animal animal : list) { animal.eat(); } } } public class TestAnimal { public static void main(String[] args) { AnimalTrainer animalTrainer = new AnimalTrainer(); //Test 1 List<Animal> animalList = new ArrayList<>(); animalList.add(new Cat("cat1")); animalList.add(new Bird("bird1")); animalTrainer.act(animalList); //可以通过编译 //Test 2 List<Cat> catList = new ArrayList<>(); catList.add(new Cat("cat2")); catList.add(new Cat("cat3")); animalTrainer.act(catList); //也可以通过编译 } }
G<? extends Y> 是 G<? extends X>的子类型(如List<? extends Cat> 是 List<? extends Animal>的子类型)。
G<X> 是 G<? extends X>的子类型(如List<Animal> 是 List<? extends Animal>的子类型)
G<?> 与 G<? extends Object>等同,如List<?> 与List<? extends Objext>等同。
这里的子类型不妨用“满足条件”去理解,比如第二条,可以理解为:满足G<X>的类型必定满足G<? extends X>
这也是通配符的应用,除了extends,通配符还可以是super,形如:List<? super Apple>,说明他的下界为Apple
那么对于下界:这个与上界不一样的地方在于
public void testAdd(List<? super Bird> list){ list.add(new Bird("bird")); list.add(new Magpie("magpie")); }这种编译合法,因为编译器认为list的参数是Bird的父类,所有包括Bird的子类都是可以添加,但不能添加Bird的父类,同理是因为无法辨别是哪一个父类
G<? super X> 是 G<? super Y>的子类型(如List<? super Animal> 是 List<? super Bird>的子类型)。
G<X> 是 G<? super X>的子类型(如List<Animal> 是 List<? super Animal>的子类型)
无界通配符:只有一个?,如List<?>,同样不能往里面添加对象
参考:http://www.linuxidc.com/Linux/2013-10/90928p2.htm以下是展示了边界的基本要素的例子:
public interface HasColor { java.awt.Color getColor(); } public interface Weight { int weight(); } public class Dimension { public int x,y,z; } public class Colored<T extends HasColor> { T item; Colored(T item){this.item = item;} public T getItem() { return item; } java.awt.Color color(){return item.getColor();} } public 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;} } public class Solid<T extends Dimension & HasColor &Weight>{ T item; public Solid(T item) { this.item = 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();} } public class Bounded extends Dimension implements HasColor, Weight { @Override public int weight() { return 0; } @Override public Color getColor() { return null; } } public class BasicBounds { public static void main(String[] args) { Solid<Bounded> solid = new Solid<Bounded>(new Bounded()); solid.color(); solid.getY(); solid.weight(); } }(1)改写例子,在继承层次上消除冗余:
public class HoldItem<T> { T item; public HoldItem(T item) { this.item = item; } T getItem(){return item;} } public class Colored2<T extends HasColor> extends HoldItem<T> { public Colored2(T item) { super(item); } java.awt.Color color(){return item.getColor();} } public class ColoredDimension2<T extends Dimension & HasColor> extends Colored2<T> { public ColoredDimension2(T item) { super(item); } int getX(){return item.x;} int getY(){return item.y;} int getZ(){return item.z;} } public class Solid2<T extends Dimension & HasColor &Weight> extends ColoredDimension2<T>{ Solid2(T item) { super(item); } java.awt.Color color(){return item.getColor();} 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(); } }
(2)改写例子,在继承层次上消除冗余:
public interface SuperPower { } public interface XRayVision extends SuperPower { void seeThroughWalls(); } public interface SuperHearing extends SuperPower { void hearSubtleNoises(); } public interface SuperSmell extends SuperPower { void trackBySmell(); } public class SuperHero<POWER extends SuperPower>{ POWER power; public SuperHero(POWER power) { this.power = power; } POWER getPower(){return power;} } public class SuperSleuth<POWER extends XRayVision> extends SuperHero<POWER> { public SuperSleuth(POWER power) { super(power); } void see(){power.seeThroughWalls();} } public class CanineHero<POWER extends SuperHearing & SuperSmell> extends SuperHero<POWER> { public CanineHero(POWER power) { super(power); } void hear(){power.hearSubtleNoises();} void smell(){power.trackBySmell();} } public class SuperHearSmell implements SuperHearing, SuperSmell { @Override public void trackBySmell() { // TODO Auto-generated method stub } @Override public void hearSubtleNoises() { // TODO Auto-generated method stub } } public class DogBoy extends CanineHero<SuperHearSmell> { public DogBoy() { super(new SuperHearSmell()); // TODO Auto-generated constructor stub } } public class EpicBattle { 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); } }
14、混型:混合多个类的能力
(1)、接口产生混型效果:
public interface TimeStamped { public long getStamp(); } public class TimeStampedImp implements TimeStamped { private final long timeStamped; public TimeStampedImp(){ timeStamped = new Date().getTime(); } public long getStamp(){ return timeStamped; } } public interface SerialNumbered { long getSeriaNumber(); } public class SerialNumberedImpl implements SerialNumbered{ private static long counter = 1; private final long seriaNumber = counter++; @Override public long getSeriaNumber() { return seriaNumber; } } public interface Basic { public void set(String val); public String get(); } public class BasicImp implements Basic{ private String value; public void set(String val){value = val;} @Override public String get() { return value; } } public class Mixin extends BasicImp implements TimeStamped,SerialNumbered{ private TimeStamped timeStamp = new TimeStampedImp(); private SerialNumbered serialNumber = new SerialNumberedImpl(); public long getStamp(){return timeStamp.getStamp();} @Override public long getSeriaNumber() { return serialNumber.getSeriaNumber(); } } public class Mixins { public static void main(String[] args) { Mixin mixin1 = new Mixin(); Mixin mixin2 = new Mixin(); mixin1.set("test String 1"); mixin2.set("test String 2"); System.out.println(mixin1.get()+" "+mixin1.getStamp()+" "+mixin1.getSeriaNumber()); System.out.println(mixin2.get()+" "+mixin2.getStamp()+" "+mixin2.getSeriaNumber()); } } //test String 1 1468222102751 1 //test String 2 1468222102767 2
public class Basic { private String value; public void set(String val){ value = val; } public String get(){ return this.value; } } public 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();} } public class TimeStamped extends Decorator{ private final long timeStamp; public TimeStamped(Basic basic) { super(basic); timeStamp = new Date().getTime(); } public long getStamp(){return timeStamp;} } public class SerialNumbered extends Decorator{ private static long counter = 1; private final long serialNumber = counter++; public SerialNumbered(Basic basic) { super(basic); } public long getSeriaNumber(){ 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())); SerialNumbered s = new SerialNumbered(new Basic()); SerialNumbered s2 = new SerialNumbered(new TimeStamped(new Basic())); } }
public 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(); if(!delegatesByMethod.containsKey(methodName)) delegatesByMethod.put(methodName, pair.first); } } } @Override 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); } 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.tuple(new BasicImp(), Basic.class), Tuple.tuple(new TimeStampedImp(), TimeStamped.class), Tuple.tuple(new SerialNumberedImpl(), 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.getSeriaNumber()); } }
标签:
原文地址:http://blog.csdn.net/monkey_dog/article/details/51768169