Java集合之泛型

来源:互联网 发布:数据录入员压力大吗 编辑:程序博客网 时间:2024/06/14 20:11

转载自 http://www.cnblogs.com/jbelial/archive/2013/03/30/2990935.html

所谓泛型就是允许在定义类、接口时指定类型形参,这个类型形参将在声明变量、创建对象时确定。增加了泛型支持后的集合,完全可以记住集合中元素的类型,并可以在编译时检查集合中元素的类型。即解决一些安全问题;同时还可以让代码变得更加简洁。

  

一.使用泛型 

  泛型的格式:通过<>来定义要操作的引用数据类型

复制代码
 1 public class GenericDemo { 2     public static void main(String[] args) 3     { 4 //        创建一个只能保存字符串的List 集合 5         List<String> strList = new ArrayList<String>() ; 6         strList.add("Generic") ;  7 //        如果存放其他对象这回出现编译错误。 8         System.out.println(strList); 9     }10 }
复制代码

 

   使用泛型的好处:

    1、将运行时期出现的ClassCastExcpetion , 转移到了编译时期。方便于程序员解决问题,让运行时期问题减少。

    2、避免了强制转换的麻烦。

  如下代码: 

复制代码
 1 class StringDemo 2 { 3     String name ;  4     public StringDemo(String name ) 5     { 6         this.name = name ;  7     } 8 } 9 public class GenericDemo {10     public static void main(String[] args)11     {12         List list = new ArrayList() ;  13         list.add(new StringDemo("烦烦烦烦烦01")) ; 14         list.add(new StringDemo("烦烦烦烦烦02")) ; 15         list.add(new StringDemo("烦烦烦烦烦03")) ; 16         list.add(new StringDemo("烦烦烦烦烦04")) ; 17         18         list.add(1000) ; 19         MyIterator(list) ; 20     }21 //    定义遍历方法:22     public static void MyIterator(List list)23     {24         Iterator it = list.iterator() ; 25         while (it.hasNext() )26         {27             StringDemo s = (StringDemo) it.next() ; 28             System.out.println(s.name);29         }30     }31 }
复制代码

 

}

  在调用MyIterator(List list) 方法时会发生ClassCastException 异常。而且在编译时是不会有任何提示,只有运行时会出现,所以使的程序存在安全隐患。

  如果使用泛型则会在编译时提示错误,而且在遍历时不需要强制转换。如: 

复制代码
 1 class StringDemo 2 { 3     String name ;  4     public StringDemo(String name ) 5     { 6         this.name = name ;  7     } 8 } 9 public class GenericDemo {10     public static void main(String[] args)11     {12         List<StringDemo> list = new ArrayList<StringDemo>() ;  13         list.add(new StringDemo("烦烦烦烦烦01")) ; 14         list.add(new StringDemo("烦烦烦烦烦02")) ; 15         list.add(new StringDemo("烦烦烦烦烦03")) ; 16         list.add(new StringDemo("烦烦烦烦烦04")) ; 17         18 //        下面一行代码在编译时会出错:19         list.add(1000) ; 20         MyIterator(list) ; 21     }22 //    定义遍历方法:23     public static void MyIterator(List list)24     {25         Iterator<StringDemo> it = list.iterator() ; 26         while (it.hasNext() )27         {   28             System.out.println( it.next().name);29         }30     }31 }
复制代码

  注意:在使用Java提供的对象时,什么时候写泛型呢?

  只要见到<> (<>就是用来接收类型的。),就要定义泛型。当使用集合时,将集合中要存储的数据类型作为参数传递到<>中即可。

二.了解泛型

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

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

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

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

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

  > ArrayList<Integer> 中的<> 念着typeof

  > ArrayList 称为原始类型

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

  > Vector<String> v = new Vector<Object>() ; //错误

  > Vector<Object> v = new Vector<String>() ; //也错误

  创建数组实例时,数组的元素不能使用参数化的类型:

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

 

 

三.定义泛型类

  除了Java提供了一些类增加了泛型支持外,我们可以定义泛型支持的类。那么在什么时候定义泛型类呢?

  当类中操作的引用数据类型不确定时可以定义泛型类。

  格式如下:

class Tools<T>{}

 

  具体操作:

复制代码
 1 //定义一个工具类Tools 2 //因为不知道要操作的类型是什么所增加泛型支持 3 class Tools<T> 4 { 5 //    包含输出函数: 6     public void sop(T t) 7     { 8         System.out.println("sop:"+t); 9     } 10 }11 //定义一个Books 类12 class Books13 {14     private String name ;15     public Books(String name)16     {17         this.name = name  ; 18     } 19 //    重写toString 方法20     public String toString()21     {22         return "name = " + name ;  23     }24 }25 public class GenericText 26 {27     public static void main(String[] args)28     { 29     //    创建一个Tools 实例tool ,定义 tool 要操作的数据类型为Books 30         Tools<Books>  tool = new Tools<Books>() ;  31     //    tool 可以操作 Books 类型,还可以操作Integer 类型和String类型。32         tool.sop(new Books("诛仙")); 33     }34 }
复制代码

 

   定义一个Tools 类 用来完成打印操作,但是应为不知道要操作的数据类型是什么,所以可以定义成泛型类。

 

 三.泛型方法

  泛型类定义的泛型,在整个类中有效,如果被方法使用,那么泛型类的对象明确要操作的具体类型后,所有要操作的类型就已经固定了。为了让不同方法可以操作不同类型,而且类型还不确定,

那么可以将泛型定义在方法上。

  定义泛型方法格式如下:

        public <T> void show(T t) 注意:<>放在修饰符后面,返回值前面        {        }

  具体操作如下:

复制代码
 1 //定义一个工具类Tools 2 //因为不知道要操作的类型是什么所增加泛型支持 3 class Tools<T> 4 { 5 //    包含输出函数: 6     public void sop(T t) 7     { 8         System.out.println("sop:"+t); 9     } 10 //    定义的泛型方法:11     public <T> void show (T t)12     {13         System.out.println("show:"+t);14     }15 }16 //定义一个Books 类17 class Books18 {19     private String name ;20     public Books(String name)21     {22         this.name = name  ; 23     } 24 //    重写toString 方法25     public String toString()26     {27         return "name = " + name ;  28     }29 }30 public class GenericText 31 {32     public static void main(String[] args)33     { 34     //    创建一个Tools 实例tool ,定义 tool 要操作的数据类型为Books 35         Tools<Books>  tool = new Tools<Books>() ;  36     //    tool 可以操作 Books 类型,还可以操作Integer 类型和String类型。37         tool.sop(new Books("诛仙")); 38         tool.show(new Books("诛仙")) ; 39 //        下面的方法编译时会报错》、:40         tool.sop(1000) ;41         tool.sop("String") ;42         43 //        但下面却不会报错,并且正常运行。44         tool.show(1000) ; 45         tool.show("String") ;46     }47 }
复制代码

 

   通过上面的代码,可以知道泛型类和泛型方法可以同时定义,且不冲突。但是也有特殊情况:静态方法不可以访问定义类上的泛型,如:

复制代码
        class Tools<T>        {            public static void method(T t)            {            }        }        上面的书写是错误的,
复制代码

  如果静态方法操作的引用数据类型不确定,可将泛型定义在方法上:

        class Tools<T>        {            public static <T> void method(T t)            {            }        }

  

  

四.泛型限定和通配符

  4.1 通配符

  类型通配符是一个问号(?):问号作为类型实参传给List 集合写作:List<?>。

复制代码
 1 //定义一个Books 类 2 class Books 3 { 4     private String name ; 5     public Books(String name) 6     { 7         this.name = name  ;  8     }  9 //    重写toString 方法10     public String toString()11     {12         return "name = " + name ;  13     }14 }15 public class GenericText 16 {17     public static void main(String[] args)18     {19 //        创建一个只能存储 Books 类型元素的 List 集合。20         List<Books> bookList = new ArrayList<Books>() ;  21         bookList.add(new Books("诛仙")) ;22         bookList.add(new Books("笑傲江湖")) ; 23         24 //        创建一个只能存储String 类型元素的List 集合25         List<String> strList = new ArrayList<String>() ;26         strList.add("Generic001") ;27         strList.add("Generic002") ;28         29         MyIterator(strList) ; 30         MyIterator(bookList) ;31         32     }33 //    定义个遍历List 集合的方法。34     public static void MyIterator(List<?>  strList)35     {36         Iterator<?> it = strList.iterator() ;37         while(it.hasNext())38         {39             System.out.println(it.next());40         }41     }42 }
复制代码

  在 MyIterator 方法中使用了类型通配符 ? ,好处是只写一个 遍历方法便可操作List 集合的遍历,缺点是不能调用元素中的特定方法。

   

  4.2 泛型限定:

    1、 ? extends E : 可以接收E类型或者E的子类型。上限定。

    2、? super E : 可以接收E类型或者E的父类型。下限定。

    

复制代码
 1 class Books 2 { 3     String name ; 4     public Books(String name) 5     { 6         this.name = name  ;  7     }   8     public String toString() 9     {10         return "name:" + name ; 11     }12 }13 class ComicBooks extends Books14 { 15     public ComicBooks(String name) {16         super(name); 17     } 18 }19 class Person_1 20 {21     String name ; 22     public Person_1 (String name)23     {24         this.name = name ;25     }26 }27 public class GenericTreeSet {28     29     public static void main(String[] args)30     {31 //        定义 TreeSet 集合 ,并且里面只存储ComicBooks类型元素,切按照自已的比较规则排序32         TreeSet<ComicBooks> bookTree = new TreeSet<ComicBooks>(new MyComparable()) ;33         34         bookTree.add(new ComicBooks("aaaaaa")) ;35         bookTree.add(new ComicBooks("aaa3gfaaa")) ;36         bookTree.add(new ComicBooks("afdfef")) ;37         bookTree.add(new ComicBooks("asdffefq")) ;38 //        调用39         MyIterator(bookTree) ; 40         41 //        下面代码编译会出现异常42         TreeSet<Person_1> p = new TreeSet<Person_1>(new MyComparable()) ;43     }44 //    定义遍历方法:只能操作Books 类型或者 Books的子类型45     public static void MyIterator(TreeSet<? extends Books> bookTree)46     {47         Iterator<? extends Books> it =  bookTree.iterator()  ;48         while(it.hasNext())49         {50             System.out.println(it.next().toString());51         }52     }53 }54 //定义比较器 :按倒序排序且该比较器只适用于 Books 类型或者 Books的子类型55 class MyComparable implements Comparator<Books>56 { 57     public int compare(Books o1 , Books o2)58     {  59         return o2.name.compareTo(o1.name);60     } 61 }
复制代码

  所以,当我们定义的某些方法只作用与某些类与其子类时,可以通过泛型限定来实现。