Java泛型学习三:泛型的表现形态

一.类型参数形态

     按照泛型类型参数的表现形态,先列出所有可能出现的,再来归纳,以List为例:

  1. Holder:原生态类型
  2. Holder<T>:最简单的泛型形态。
  3. Holder<T extends Number>:有限制形式类型参数。
  4. Holder<T super Number>:有限制形式类型参数。可惜的是没有这种语法。
  5. Holder<? extends T>:子类型通配符。
  6. Holder<? super T>:超类型通配符。
  7. Holder<?>:无界限定符。
  8. Holder<Object>:同List。

 

二.有限制形式类型参数

      Holder<T extends Number>,实际参数类型将只能是Number的子类型。

 

三.通配符

  1. 子类型通配符:能读不能写。我知道Holder里持有的永远是T的子类,所以get必定就是T类型;但我只知道是T的子类型,但具体是什么,没法确定,为了保证类型安全,不允许set,当然能set(null),因为null恰好不需要类型。
  2. 超类型通配符:能写不能读。我知道Holder里持有的永远是T的超类,那我set一个T类型的对象当然是可以的(T的子类当然也可以),当然set(null)也完全没问题;但到底是哪个超类呢,不确定,所以get操作类型是不确定的,只能get出一个Object。
  3. 无界通配符:不能读不能写。没有任何界限,我永远不知道用户想使用一个什么类型,get操作也只能get出一个Object,set操作只能set一个null。
  4. 总结:PECS produces-extends, consumer-super。produces && consumer请使用原生类型。
    package com.jyz.study.jdk.generic;
    
    /**
     * 通配符
     * @author JoyoungZhang@gmail.com
     *
     */
    public class Wildcards {
    
    	//原生类型
    	static void rawArgs(Holder holder, Object arg){
    		holder.get();
    		holder.set(arg);
    		holder.set(new Wildcards());
    	}
    	
    	//无界通配符
    	static void unboundedArg(Holder<?> holder, Object arg){
    		Object object = holder.get();
    		T t = holder.get();//compile error, don't hava any T
    		holder.set(arg);//compile error
    		holder.set(null);
    	}
    	
    	//子类型通配符
    	static <T> T wildSubtype(Holder<? extends T> holder, T arg){
    		holder.set(arg);//compile error
    		holder.set(null);
    		T t = holder.get();
    		return t;
    	}
    	
    	//超类型通配符
    	static <T> T wildSupertype(Holder<? super T> holder, T arg){
    		holder.set(arg);
    		holder.set(null);
    		T t = holder.get();//compile error
    		Object obj = holder.get();
    		return t;
    	}
    	
    	
    	class Holder<T> {
    		private T element;
    		
    		public Holder() {
    		}
    
    		public Holder(T element) {
    			this.element = element;
    		}
    		
    		public T get(){
    			return element;
    		}
    		
    		public void set(T arg){
    			this.element = arg;
    		}
    		
    		public boolean equals(Object obj){
    			if(!(obj instanceof Holder)){
    				return false;
    			}
    			Holder<?> holder = (Holder<?>)obj;
    			return element == null ? holder.element == null : element.equals(holder.element);
    		}
    	}
    }
    
      

四.四者区别

  1. List:原生类型,没有泛型存在,List存在的是Object类型,取出来也是Object类型,需要自己做类型转换。
  2. List<Object>:List实际上就是List<Object>,我觉得没必要显示的来说明一下List<Object>。
  3. List<?>:具有某种特定类型的非原生List,只是这个类型还不确定,将有使用者去确定。确定后,就永远存在这个类型的对象,取出来也是这个类型的变量。
  4. List<? extends Object>:具有某种特定类型的非原生List,这个类型也还不确定,将有使用者去确定,并且,这个类型必须是Object的子类。因为恰好Java里任何类都是Object的子类,所以我觉得List<? extends Object>意义不大,使用List<?>足够了,如果换成List<? extends Number>这个语法才能发挥威力。

五.什么使用T 什么时候使用?

  1. 定义一个泛型类或泛型接口时,使用<T> <T extends 具体类型>。
  2. 引用泛型类时,使用<?> <? extends T> <? super T>。一般是将泛型类或接口定义成一个变量(成员变量和局部变量),或将泛型类或接口作为返回值时。
  3. 下面这个泛型类差不多涵盖了泛型最复杂的表现形态。能轻松写出来,使用泛型对你来说就是小事了。
    package com.jyz.study.jdk.generic;
    
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.List;
    
    /**
    * 什么时候用T 什么时候用?
    * @author JoyoungZhang@gmail.com
    * http://zy19982004.iteye.com/blog/1978028
    *
    */
    public class TOrQuestionMark<TT> {
    
    	protected Holder<? extends Throwable> list1;
    	protected Holder<? super Throwable> list2;
    	private Holder<? extends Throwable> test1(Holder<? extends Throwable> list){
    		return list;
    	}
    	private Holder<? super Throwable> test2(Holder<? super Throwable> list){
    		return list;
    	}
    	
    	protected List<? extends TT> list3;
    	protected List<? super TT> list4;
    	protected List<? extends TT> test3(List<? extends TT> list){
    		return list;
    	}
    	protected List<? super TT> test4(List<? super TT> list){
    		return list;
    	}
    	
    	public void init() {
    		list1 = new Holder<RuntimeException>();
    		list1 = new Holder<IOException>();
    		list2 = new Holder<Throwable>();//没办法Throwable已经没有超类了,用自己
    		Holder<? extends Throwable> listreturn1 = test1(new Holder<IOException>());
    		Holder<? super Throwable> listreturn2 = test2(new Holder<Throwable>());
    		
    		//以下依赖TT,先实例化tq
    		TOrQuestionMark<Exception> tq = new TOrQuestionMark<Exception>();
    		tq.list3 = new ArrayList<RuntimeException>();
    		tq.list3 = new ArrayList<IOException>();
    		tq.list4 = new ArrayList<Throwable>();
    		List<? extends Exception> listreturn3 = tq.test3(new ArrayList<RuntimeException>());
    		List<? super Exception> listreturn4 = tq.test4(new ArrayList<Throwable>());
    	}
    
    }
    
    class Holder<T extends Throwable>{
    	private T obj;
    	public void set(T obj){
    		this.obj = obj;
    	}
    	public T get(){
    		return obj;
    	}
    }
    //sorry,compile error!!!!!
    //class Holder2<T super IOException>{
    //	private T obj;
    //	public void set(T obj){
    //		this.obj = obj;
    //	}
    //	public T get(){
    //		return obj;
    //	}
    //}
    
     
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值