Java笔记 _ 泛型

泛型的本质:参数类型的应用。将所操作的数据类型定义为一个参数,并在应用的时候指定类型。

1.为什么使用泛型
    在JDK1.5之前,泛型程序设计是通过继承来实现的,例如:   

List list = new ArrayList();	//当加入或取出元素时,都被当成Object类型来看待
list.add(new Integer(10));
list.add("10");

   那么,在取出元素时候,要知道取出元素的类型,并进行强制转换       

Integer a = (Integer) list.get(0); 	//要求强制转换成Integer类型
Integer b = (Integer) list.get(1);	//运行时报错 java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer


   如果使用泛型设计时,编译器进行参数检查

List<Integer> list = new ArrayList<Integer>();
list.add(new Integer(10));
list.add("10");  //编译器报错
list.add(10);

  同样,取出时不用进行强制类型转换

Integer a = list.get(0);
Integer b = list.get(1);


泛型的优点:让编译器保留参数的类型信息,执行类型检查,执行类型转换操作。  可读性+安全性提升。

2.泛型的类型擦除
     在Java源文件编译生成的字节码中是不包含泛型的类型信息的,即泛型只存在编译期。
     擦除后将泛型类型替换成限定类型(无限定类型的变量用Object)

List<Integer> list1 = new ArrayList<Integer>();
List<String> list2 = new ArrayList<String>();

System.out.println(list1.getClass() == list2.getClass());   // true
System.out.println(list1.getClass().getName());	//java.util.ArrayList
System.out.println(list2.getClass().getName());	//java.util.ArrayList

所以,List<Integer> 和 List<String>  使用的是同一份字节码,它们在编译之后都会变成原始类型List。


3.泛型的继承: 不存在任何的继承关系


4.通配符类型


当要遍历一个集合的所有元素时:

void printCollection(Collection c) {
		Iterator it = c.iterator();
		for(int k=0; k<c.size(); k++) {
			System.out.println(i.next());
		}
	}


但泛型的版本只能接受元素类型为Object类型的集合void printCollection(Collection<Object> c),如果有ArrayList<String> 集合,则编译出错。
在老版本中可以打印任何类型的集合,设计人员设计了通配符"?"来搞定,使新版本也能遍历任何的类型。

void printCollection(Collection<?> c) {
		for(Object o : c) { 	//合法,因为存储类型一定是Object的子类型
			System.out.println(o);
		}	
	}


注:不能向Collection<?>容器实例中加入任何非null元素,因为编译器无法确定添加对象的类型

边界通配符: Producer Extends, Consumer Super
          上界:ArrayList<? extends Number> collection = null;
                                 匹配Number类以及它的子类
          下界:ArrayList<? super Integer> collection = null;
                                  匹配Integer类以及它的超类(Integer Number Object)
  
5.泛型的方法
  拷贝一个数组中所有的对象到集合中的方法

 static void fromArraytoCollection(Object[] a, Collection<> c) {
  	for(Object o : a) {
  		c.add(o);  //Error	
  	}	
  }

 使用泛型方法

static <T> void fromArraytoCollection(Object[] a, Collection<T> c) {
  	for(T o : a) {
  		c.add(o);	
  	}	
  }


  
6.泛型的约束和局限性
     1) 泛型类的静态字段和静态方法无效、不能实例化对象、instanceOf操作

            对 class GenericClass<T>
            由于类型的擦除,JVM只有一个GenericClass类,所以GenericClass类的静态字段和静态方法的定义             中不能使用T(多个),T只是与GencricClass实例相关的信息.
            T只在编译时被编译器理解,因此也就不能与运行时被JVM理解并执行其代表的操作的操作符(如instanceof 和new)联用

    2)不能出创建参数化类型数组

List<Integer>[] ls = new List<Integer>[10]; // error
List<?>[] ls = new List<?>[10];   //ok


   可以声明一个数组,然后进行强制转换

ls = (List<Integer>[])new List<?>[10];



 

你可能感兴趣的:(java)