Java泛型

  1. 泛型的主要功能是提供编译时类型检查,原生态类型(即不使用泛型)躲避了编译时类型检查,不推荐使用,在IDE中编辑时会有警告。
  2. 泛型有子类化(subtyping)规则。参数化类型的List<String>是原生态类型List的一个子类型,但不是参数化类型List<Object>的子类型。在泛型中不承认参数之间的继承关系。但是ArrayList<Object>是List<Object>的子类。与泛型刚好相反,数组是协变(covariant)的,即Sub为Super的子类时,Sub[]就是Super[]的子类。创建泛型数组是非法的,比如new List<E>[]、new List<String>[]、new E[]都是非法的,但是new Stack<int[]>是合法的。
  3. 无限制的通配符类型。如果不确定或不关心实际的类型参数,就可用一个?代替,如List<?>,使用无限制的通配符类型在IDE中不会有警告。
  4. 在类文字(class literal)中必须使用原生态类型,List.class,String[].class,int.class都是合法的,List<String>.class,List<?>.class是不合法的。List<String>和List<Integer>共用一个Class对象,即List.class。
  5. 泛型信息在运行时被擦除。下面是利用泛型来使用instanceof的首先方法:
    if(o instanceof Set){
    	Set<?> m=(Set<?>)o;
    	//......
    }
    instanceof是在运行时决定的,而泛型信息在运行时被擦除,所以此时要使用原生态的Set。把o转变成通配符类型Set<?>,这是个受检查的(checked)转换,因此不会导致编译时警告。
  6. 当无法消除警告,而我们又可以保证代码是类型安全时,可以用一个@SuppressWarnings("unchecked")注解来禁止这些警告,同时加一条注释,说明为什么这么做是安全的。SuppressWarnings可以用在任何粒度的级别中,从单独的局部变量声明到整个类都可以,当然应该在尽可能小的范围内使用。
  7. 泛型类类似于C++中的模板类。
    public class Stack<E> {
    	private E[] eles;
    	private int size=0;
    	private static final int DEFAULT_INITIAL_CAPACITY=16;
    	@SuppressWarnings("unchecked")
    	public Stack(){			//定义构造函数时不需要使用参数标记
    		//eles=new E[DEFAULT_INITIAL_CAPACITY];		错误。不能创建不可具化(non-reifiable)的类型数组。
    		eles=(E[])new Object[DEFAULT_INITIAL_CAPACITY];			//编译器不能保证你的强制转换是类型安全的,所以要使用SuppressWarnings
    	}
    	public void push(E e){
    		ensureCapacity();
    		eles[size++]=e;
    	}
    	public E pop(){
    		if(size==0)
    			throw new EmptyStackException();
    		E result=eles[--size];
    		eles[size]=null;		//类自己管理内在时记得要及时释放内在,免得内在泄漏
    		return result;
    	}
    	private void ensureCapacity(){
    		if(eles.length==size)
    			eles=Arrays.copyOf(eles, 2*size+1);
    	}
    }
  8. 泛型中的参数不能是基本数据类型。Stack<int>是错误的。
  9. 泛型方法。
    public static <E> Set<E> union(Set<E> s1,Set<E> s2){
    	Set<E> result=new HashSet<E>(s1);
    	result.addAll(s2);
    	return result;
    }
    静态工厂方法尤其适合泛型化。
    比如Map<String,List<String>> var=new HashMap<String,List<String>>();类型出现在等号两边显得有些冗余。如果Map定义了如下使用了泛型的静态工厂方法
    public static <K,V> HashMap<K,V> newHashMap(){
    	return new HashMap<K,V>();
    }
    那么用Map的这个静态工厂方法创建对象代码就比较简洁了:
    Map <String,List<String>> var=newHashMap();
  10. <E extends Number>、<T extends Comparable<T>>、List<? extends Number>、static <E> List<E> asList(E[] a)都是可以的。
  11. 区别<? extends T>和<? suprt T>。如果参数化类型表示一个T生产者,就用<? extends T>,如果表示一个T消费者,就用<? suprt T>。
  12. 类的类型从字面上看不是简单的Class,而是Class<T>,比如String.class属于Class<String>类型,Integer.class属于Class<Integer>类型。
    public class Favorites {
    	private Map<Class<?>,Object> favorites=new HashMap<Class<?>,Object>();
    	public <T> void putFavorite(Class<T> type,T instance){
    		if(type==null)
    			throw new NullPointerException("Type is null");
    		favorites.put(type, instance);
    	}
    	public <T> T getFavorite(Class<T> type){
    		return type.cast(favorites.get(type));     //利用CLass的cast方法,将对象引用
    	}
    	public static void main(String[] args){
    		Favorites f=new Favorites();
    		f.putFavorite(Integer.class, 2);
    		f.putFavorite(Class.class,Favorites.class);
    		int i=f.getFavorite(Integer.class);
    		Class<?> c=f.getFavorite(Class.class);
    		System.out.printf("%d\t%s\n",i,c.getName());
    	}
    }
    输出:2 general.Favorites
    上述代码中的Map的key值可以是String或者String[],但不能是List<String>,因为List<String>.class是语法错误。





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值