- 泛型的主要功能是提供编译时类型检查,原生态类型(即不使用泛型)躲避了编译时类型检查,不推荐使用,在IDE中编辑时会有警告。
- 泛型有子类化(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[]>是合法的。
- 无限制的通配符类型。如果不确定或不关心实际的类型参数,就可用一个?代替,如List<?>,使用无限制的通配符类型在IDE中不会有警告。
- 在类文字(class literal)中必须使用原生态类型,List.class,String[].class,int.class都是合法的,List<String>.class,List<?>.class是不合法的。List<String>和List<Integer>共用一个Class对象,即List.class。
- 泛型信息在运行时被擦除。下面是利用泛型来使用instanceof的首先方法:
instanceof是在运行时决定的,而泛型信息在运行时被擦除,所以此时要使用原生态的Set。把o转变成通配符类型Set<?>,这是个受检查的(checked)转换,因此不会导致编译时警告。if(o instanceof Set){ Set<?> m=(Set<?>)o; //...... }
- 当无法消除警告,而我们又可以保证代码是类型安全时,可以用一个@SuppressWarnings("unchecked")注解来禁止这些警告,同时加一条注释,说明为什么这么做是安全的。SuppressWarnings可以用在任何粒度的级别中,从单独的局部变量声明到整个类都可以,当然应该在尽可能小的范围内使用。
- 泛型类类似于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); } }
- 泛型中的参数不能是基本数据类型。Stack<int>是错误的。
- 泛型方法。
静态工厂方法尤其适合泛型化。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定义了如下使用了泛型的静态工厂方法
那么用Map的这个静态工厂方法创建对象代码就比较简洁了:public static <K,V> HashMap<K,V> newHashMap(){ return new HashMap<K,V>(); }
Map <String,List<String>> var=newHashMap();
- <E extends Number>、<T extends Comparable<T>>、List<? extends Number>、static <E> List<E> asList(E[] a)都是可以的。
- 区别<? extends T>和<? suprt T>。如果参数化类型表示一个T生产者,就用<? extends T>,如果表示一个T消费者,就用<? suprt T>。
- 类的类型从字面上看不是简单的Class,而是Class<T>,比如String.class属于Class<String>类型,Integer.class属于Class<Integer>类型。
输出:2 general.Favoritespublic 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()); } }
上述代码中的Map的key值可以是String或者String[],但不能是List<String>,因为List<String>.class是语法错误。
Java泛型
最新推荐文章于 2024-10-30 20:29:44 发布