码迷,mamicode.com
首页 > 编程语言 > 详细

java笔记 泛型

时间:2016-07-13 17:22:00      阅读:290      评论:0      收藏:0      [点我收藏+]

标签:

通过几个例子来表现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()+" ");
	}
}

5、泛型创建生成器:工厂方法的一种应用

生成器接口和实体类

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

7、简化创建容器对象的工具类:

//一个能节省代码的容器创造类
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 15
10、构建复杂模型的例子:比如一个商店里面有多个集合:走廊包括货架,货架包括商品,这就存在一种嵌套关系:

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

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


(3)、动态代理混型:结合上面的工具类

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




java笔记 泛型

标签:

原文地址:http://blog.csdn.net/monkey_dog/article/details/51768169

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!