黑马程序员-Java泛型

 

泛型

泛型是对Java语言的类型系统的一种扩展,以支持创建可以按类型进行参数化的类。

没有使用泛型时,只要是对象,不管是什么类型的对象,都可以存储进同一个集合中。使用泛型集合,可以将一个集合中的元素限定为一个特定类型,集合中只能存储同一个类型的对象,这样更安全;并且当从集合获取一个对象时,编译器也可以知道这个对象的类型,不需要对对象进行强制类型转换,更方便。

示例:

       public static void main(String[] args) throws Exception {
            Constructor<String> constructor = String.class.getConstructor(StringBuffer.class);
            String str = constructor.newInstance( new StringBuffer("abc" ));
            System. out.println(str.charAt(2));
             //结果:c
      }

  引入泛型后,创建实例对象时就不需要类型转换了。

 

泛型的内部原理

泛型时提供给javac编译器使用的,可以限定集合中的输入类型,让编译器挡住源程序中的非法输入。但是,编译器编译带类型说明的集合时会去掉“类型”信息,目的就是使程序运行效率不受影响。因此,对于参数化的泛型类型,getClass()方法的返回值和原始类型完全一样。

            ArrayList<String> collection1 = new ArrayList<String>();
            ArrayList collection2 = new ArrayList();
            System. out.println(collection1.getClass() == collection2.getClass());
             //结果:true

 

由于编译生成的字节码会取缔哦泛型的类型信息,只要能跳过编译器,就可以往某个泛型集合中加入其他类型的数据。

示例:用反射得到集合,再调用其add方法

       public static void main(String[] args) throws Exception {
            ArrayList<Integer> collection1 = new ArrayList<Integer>();
            collection1.getClass().getMethod( "add",Object.class).invoke(collection1, "abc");
            System. out.println(collection1.get(0));
      }

  

ArrayList<E>类定义和ArrayList<Integer>类引用中涉及如下术语:

整个称为ArrayList<E>泛型类型

ArrayList<E>中的E称为类型变量或类型参数

整个ArrayList<Integer>称为参数化的类型

ArrayList<Integer>中的Integer称为类型参数的实例或实际类型参数

ArrayList<Integer>中的<>念着typeof

ArrayList称为原始类型

 

参数化类型与原始类型的兼容性:

参数化类型可以引用一个原始类型的对象,编译报告警告,例如:Collection <String> c = new Vector();//考虑到对以前代码的兼容性,编译器是可以通过的

原始类型可以引用一个参数化类型的对象,编译报告警告,例如:Collection  c = new Vector<String>();//原来的方法接收一个集合参数,新的类型也要能传进去

 

参数化类型不考虑类型参数的继承关系:

Vector<String> v = new Vector<Object>();    //错误!可以的话,那么以后从v中取出的对象当作String用,而v实际指向的对象中可以加入任意的类型对象

Vector<Object> v = new Vector<String>();    //错误!可以的话,那么以后可以向v中加入任意的类型对象,而v实际指向的集合中只能装String类型的对象

 

编译器不允许创建泛型变量的数组。即在创建数组实例时,数组的元素不能使用参数化的类型。

例如:Vector<Integer> vectorList[] = new Vector<Integer>[10];     //错误

 

泛型的通配符扩展应用

问题:

定义一个方法,该方法用于打印出任意参数化类型的集合中的所有数据,该方法如何定义呢?

如果将printCollection中的参数设置为Collection<Object>类型,那么传入参数的时候,如果参数化的类型是其他类型,就会报错。

       public static void main(String[] args) {
             ArrayList<Integer> collection = new ArrayList<Integer>();
             printCollection(collection);
      }
 
 //public static void printCollection(Collection<Object> collection){}

 public static void printCollection(Collection<?> collection){
             //collection.add(1);//报错
            System. out.println(collection.size());
            for(Object obj : collection){
                  System. out.println(obj);
            }
      }

  

Java1.5中使用?通配符可以引用其他各种参数化的类型,?通配符定义的变量主要用作引用。此时,printCollection方法中可以调用与参数化无关的方法,不能调用与参数化有关的方法。上面的示例Collection类中的add(E e)方法就与参数化有关,不能调用。size()方法与参数化无关就可以调用。

 

 

限定通配符的上边界:

正确:Vector<? extends Number> x = new Vector<Integer>();

错误:Vector<? extends Number> x = new Vector<String>();

限定通配符的下边界:

正确:Vector<? super Integer> x = new Vector<Number>();

错误:Vector<? super Integer> x = new Vector<Byte>();

注意:限定通配符总是包括自己。

 

posted @ 2015-06-01 12:53  troy健  阅读(140)  评论(0编辑  收藏  举报