• Java基础-泛型


                        Java基础-泛型

                                        作者:尹正杰

    版权声明:原创作品,谢绝转载!否则将追究法律责任。

    一.泛型的引入

      由于集合可以存储任意类型的元素,导致取出时,如果出现强转就会引发运行时异常(ClassCastException)。怎么解决这个问题呢?使用集合时,必须明确集合中元素的类型。这种方式称为泛型。一旦我们给一个集合定义泛型,那就意味着这个集合只能传入指定的数据类型。

     1 /*
     2 @author :yinzhengjie
     3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
     4 EMAIL:y1053419035@qq.com
     5 */
     6 
     7 package cn.org.yinzhengjie.note;
     8 
     9 import java.util.ArrayList;
    10 import java.util.Collection;
    11 import java.util.Iterator;
    12 
    13 public class GenericDemo {
    14     public static void main(String[] args) {
    15         Collection coll = new ArrayList();
    16         coll.add("yinzhengjie");
    17         coll.add("尹正杰");
    18         coll.add("Java");
    19         coll.add(2018);
    20         
    21         Iterator it = coll.iterator();
    22         while(it.hasNext()){
    23             Object obj = it.next();
    24             //在进行强转操作时,需要对数据进行判断,判断传入的数据是否为String类型,如果是则进行向下转型操作!
    25             if(obj instanceof String) {
    26                 String str = (String)obj;
    27                 System.out.println(str.toUpperCase());
    28             }
    29         }
    30     }
    31 }
    32 
    33 
    34 /*
    35 以上代码执行结果如下:
    36 YINZHENGJIE
    37 尹正杰
    38 JAVA
    39 */

      JDK1.5出现新的安全机制,保证程序的安全性,就是我们今天要说明的泛型,它指明了集合中存储数据的类型。

    二.泛型的定义与使用

       看了上面的代码,你可以明显的发现可以往一个结合里面塞各种数据类型,但是在遍历该集合的每一个元素时,你会清楚的知道,需要对不同的数据类型做相应的向下转型,这样才能使用元素本身的方法。这样就给程序员带了很多麻烦,需要对引用数据类型做断言操作,如果在定义集合时就规定好传入的数据类型就可以避免断言操作啦!我们可以对上面的代码用泛型对代码进行改进如下:

     1 /*
     2 @author :yinzhengjie
     3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
     4 EMAIL:y1053419035@qq.com
     5 */
     6 
     7 package cn.org.yinzhengjie.note;
     8 
     9 import java.util.ArrayList;
    10 import java.util.Collection;
    11 import java.util.Iterator;
    12 
    13 public class GenericDemo {
    14     public static void main(String[] args) {
    15         //后面的ArrayList是可以不写数据类型的,默认与前面的相同,我们称为菱形语法!
    16         Collection<String> coll = new ArrayList<>();
    17         coll.add("yinzhengjie");
    18         coll.add("尹正杰");
    19         coll.add("Java");
    20 //        coll.add(2018);        #这里的基本数据类型会自动装箱为Integer类型,很显然和String不是一种类型,无法添加到该集合
    21         
    22         //创建迭代器的时候也会传入相应的泛型。
    23         Iterator<String> it = coll.iterator();
    24         while(it.hasNext()) {
    25             //此处也不需要做向下转型,直接就可以调用String的方法啦!
    26             System.out.println(it.next().toUpperCase());
    27         }
    28     }
    29 }
    30 
    31 
    32 /*
    33 以上代码执行结果如下:
    34 YINZHENGJIE
    35 尹正杰
    36 JAVA
    37 */

       综上所述,我们可以归纳泛型有两大好处:

          1>.将运行时期的ClassCastException转移到了编译时期变成了编译失败。

          2>.避免了类型转换的麻烦。

    三.Java中的伪泛型

       java中的泛型是伪泛型(也就是假的泛型)。Java中的泛型只是一种编译手段。比如:“ArrayList<Integer> arr = new ArrayList<>();”很明显就是泛型,当然你调用"arr.add(Integer number)"方法往arr集合中添加元素时,若该元素不是Integer类型时就会编译失败,若该元素是Integer类型,则会编译成功。但是编译后的字节码文件(*.class)中是没有泛型的。

      Java中泛型只是在编译时候才会体现,一旦编译成功后的字节码文件中压根就没有泛型的踪影,这就是Java的伪泛型。那么问题来了,既然Java运行时并没有泛型那还能保证数据的安全性吗?答案是肯定的,因为在编译的时候,不符合的数据类型是不会让代码编译通过的。所以Java靠编译手段完全是可以保证安全性。Java反编译字节码文件后你会发现源代码是没有泛型的哟!

    四.自定义泛型类

     1 /*
     2 @author :yinzhengjie
     3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
     4 EMAIL:y1053419035@qq.com
     5 */
     6 
     7 package cn.org.yinzhengjie.note;
     8 
     9 import java.util.Date;
    10 
    11 //定义泛型类
    12 class Student<T>{
    13     T score;//String score;Integer score;
    14     //泛型方法
    15     public void setScore(T t){
    16         score = t;
    17     }
    18     public T getScore(){
    19         return score;
    20     }
    21 }
    22 
    23 public class GenericDemo{
    24     public static void main(String[] args) {
    25         
    26         Student<Integer> s1 = new Student<Integer>();  //指定泛型为Integer类型
    27         s1.setScore(10);                  //传递参数的时候就必须为Integer类型
    28         System.out.println(s1.getScore());
    29             
    30         Student<String> s2 = new Student<>();      //指定泛型为String类
    31         s2.setScore("优秀");            //传参数的时候就必须为String类型
    32         System.out.println(s2.getScore());
    33     }
    34 
    35 }
    36 
    37 
    38 /*
    39 以上代码执行结果如下:
    40 10
    41 优秀
    42 */

    五.自定义泛型方法

     1 /*
     2 @author :yinzhengjie
     3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
     4 EMAIL:y1053419035@qq.com
     5 */
     6 
     7 package cn.org.yinzhengjie.note;
     8 
     9 import java.util.Date;
    10 
    11 
    12 
    13 import java.util.Date;
    14 
    15 //定义泛型方法.
    16 class Generic1{
    17     //泛型方法
    18     public <T>void show(T t){//相当于Object
    19         System.out.println(t);
    20     }
    21 }
    22 
    23 public class GenericDemo{
    24 
    25     public static void main(String[] args) {
    26 
    27         Generic1 g1 = new Generic1();
    28         
    29         g1.show("yinzhengjie");        //存储String类型
    30         g1.show(2018);                //存储Integer类型
    31         g1.show(new Date());        //存储Date类型
    32         
    33     }
    34 }
    35 
    36 
    37 /*
    38 以上代码执行结果如下:
    39 yinzhengjie
    40 2018
    41 Wed Apr 25 13:25:45 GMT+08:00 2018
    42 */

    六.自定义泛型接口

     1 /*
     2 @author :yinzhengjie
     3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
     4 EMAIL:y1053419035@qq.com
     5 */
     6 
     7 package cn.org.yinzhengjie.note;
     8 
     9 //定义泛型接口
    10 interface InterA<T>{
    11     public abstract void show(T t);
    12 }
    13 
    14 //接口实现类
    15 //实现类知道接口中的具体类型,此时实现类可以是非泛型类
    16 class A implements InterA<String>{
    17 
    18     @Override
    19     public void show(String t) {
    20         System.out.println(t);
    21     }
    22     
    23 }
    24 
    25 //实现类在实现接口时,本身还是一个泛型类
    26 class B<T> implements InterA<Integer>{
    27     @Override
    28     public void show(Integer t) {
    29         System.out.println(t);
    30     }
    31     
    32     public void show2(T t) {
    33         System.out.println(t);
    34     }
    35     
    36 }
    37 
    38 //实现类也不知道接口中泛型的具体类型,那么子类也是一个泛型类
    39 class C<T> implements InterA<T>{
    40 
    41     @Override
    42     public void show(T t) {
    43         System.out.println(t);
    44     }
    45 }
    46 
    47 public class GenericDemo{
    48     public static void main(String[] args) {
    49         A a = new A();
    50         a.show("yinzhengjie");
    51         
    52         
    53         B<String> b = new B<>();
    54         b.show(2018);
    55         b.show2("尹正杰");
    56         
    57         C<Integer> c = new C<>();
    58         c.show(5200);
    59     }
    60 }
    61 
    62 
    63 
    64 /*
    65 以上代码执行结果如下:
    66 yinzhengjie
    67 2018
    68 尹正杰
    69 5200
    70 */

    七.泛型的通配符

     1 /*
     2 @author :yinzhengjie
     3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
     4 EMAIL:y1053419035@qq.com
     5 */
     6 
     7 package cn.org.yinzhengjie.note;
     8 
     9 import java.util.ArrayList;
    10 import java.util.Collection;
    11 import java.util.HashSet;
    12 import java.util.Iterator;
    13 
    14 public class GenericDemo{
    15     public static void main(String[] args) {
    16         ArrayList<String> array = new ArrayList<String>();
    17         HashSet<Integer> set = new HashSet<Integer>();
    18         array.add("yinzhengjie");
    19         array.add("尹正杰");
    20         
    21         set.add(2018);
    22         set.add(328);
    23         
    24         iterator(array);
    25         iterator(set);
    26         
    27     }
    28     
    29     //定义方法,可以同时迭代2个集合,使用泛型的通配符"?"
    30     public static void iterator(Collection<?> coll) {
    31         //泛型通配符“?”可以匹配所有的数据类型。
    32         Iterator<?> it = coll.iterator();
    33         while(it.hasNext()) {
    34             //it.next())获取的对象应该是Object类型,此处我们最好不要强制转型,因为我们不知道传入的迭代对象是set还是array!
    35             System.out.println(it.next());
    36         }
    37     }
    38     
    39     
    40 }
    41 
    42 
    43 
    44 /*
    45 以上代码执行结果如下:
    46 yinzhengjie
    47 尹正杰
    48 2018
    49 328
    50 */

    八.泛型的限定

      1>.* ? extends Animal : 上限限定,限制的是父类,即Animal和它的子类可以使用.

      2>.* ? super Animal: 下限限定,限制的是子类,即Animal和它的父类都可以使用.

      1 /*
      2 @author :yinzhengjie
      3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
      4 EMAIL:y1053419035@qq.com
      5 */
      6 
      7 package cn.org.yinzhengjie.note;
      8 
      9 
     10 import java.util.Collection;
     11 
     12 /*
     13  * 泛型类是没有多态性
     14  * 泛型如何实现类似于多态性?
     15  *     通配符能实现
     16  *   ? 
     17  *   ? extends Animal : 上限限定,Animal和它的子类可以使用
     18  *   ? super Animal: 下限限定,Animal和它的父类都可以使用
     19  * 
     20  * 类型限定的使用
     21  * 
     22  */
     23 class Animal {
     24 
     25 }
     26 
     27 class Dog extends Animal {
     28 
     29 }
     30 
     31 class Cat extends Animal {
     32 
     33 }
     34 
     35 class Demo<T> {
     36 
     37 }
     38 
     39 class DemoTest {
     40     public void test6(Collection<? extends Animal> c){//
     41         //由于不知道具体的类型,所以不能放东西
     42 //        c.add(null);
     43         //由于元素的类型要么是Animal,要么是它的子类,都可以使用Animal去接
     44         for (Animal animal : c) {
     45         
     46         }
     47     }
     48     public void test7(Collection<? super Animal> c){//
     49         //由于不知道具体的类型,但是我知道都是Animal或者是它的父类,Animal和它的子类可以自动转成Animal
     50         c.add(new Animal());
     51         c.add(new Dog());
     52         c.add(new Cat());
     53 //        c.add(new Object());
     54         //由于不知道类型的上限,所以不能往外拿元素,Object是所有类的鼻祖,此处我们需要忽略它。
     55 //        for (Object object : c) {
     56 //            
     57 //        }
     58     }
     59     
     60     public void test(Demo<Animal> d) {// 多态?Demo<Dog>
     61 
     62     }
     63     public void test2(Demo<?> d) {// 相当于Object,但是如果你写Object的话,那么传入的对象就只能是Object啦!
     64 
     65     }
     66     public void test3(Demo<Object> d) {// 相当于Object,调用者此处传入的必须是Object类,不能是其子类。
     67         
     68     }
     69     
     70     public void test4(Demo<? extends Animal> d){//Animal或者它的子类
     71         
     72     }
     73     public void test5(Demo<? super Animal> d){//Animal或者它的父类都可以使用
     74         
     75     }
     76 }
     77 
     78 public class GenericDemo1 {
     79 
     80     public static void main(String[] args) {
     81         DemoTest dt = new DemoTest();
     82         
     83         
     84         dt.test5(new Demo<Animal>());
     85         dt.test5(new Demo<Object>());
     86 //        dt.test5(new Demo<Dog>());//NG
     87 
     88 //        dt.test4(new Demo<Animal>());
     89 //        dt.test4(new Demo<Dog>());
     90 //        dt.test4(new Demo<Cat>());
     91 //        dt.test4(new Demo<Object>());//NG
     92         
     93         
     94         
     95 //        dt.test2(new Demo<Integer>());
     96 
     97         // Demo<Dog> d = new Demo<Dog>();
     98         // Demo<Animal> d2 = new Demo<>();
     99 
    100         // dt.test(d2);//Demo<Animal> Demo<Dog>
    101 
    102     }
    103 
    104 }

    案例展示:

     将酒店员工,厨师,服务员,经理,分别存储到3个集合中,定义方法可以同时遍历这3个集合,遍历三个集合的同时,可以调用工作方法。

     1 /*
     2 @author :yinzhengjie
     3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
     4 EMAIL:y1053419035@qq.com
     5 */
     6 
     7 package cn.org.yinzhengjie.note;
     8 
     9 public abstract class Employee {
    10     public  abstract  void Work();
    11 }
    Employee.java 文件内容
     1 /*
     2 @author :yinzhengjie
     3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
     4 EMAIL:y1053419035@qq.com
     5 */
     6 
     7 package cn.org.yinzhengjie.note;
     8 
     9 public class Waiter extends Employee {
    10     private String name;
    11     private String department;
    12     public Waiter() {
    13         super();
    14     }
    15     public Waiter(String name, String department) {
    16         super();
    17         this.name = name;
    18         this.department = department;
    19     }
    20     public String getName() {
    21         return name;
    22     }
    23     public void setName(String name) {
    24         this.name = name;
    25     }
    26     public String getDepartment() {
    27         return department;
    28     }
    29     public void setDepartment(String department) {
    30         this.department = department;
    31     }
    32     @Override
    33     public void Work() {
    34         System.out.println(this.getName()+" 正在工作中......");
    35     }
    36     
    37     
    38     
    39 }
    Waiter.java 文件内容
     1 /*
     2 @author :yinzhengjie
     3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
     4 EMAIL:y1053419035@qq.com
     5 */
     6 
     7 package cn.org.yinzhengjie.note;
     8 
     9 public class Cook extends Employee {
    10     private String name;
    11     private String department;
    12     public String getName() {
    13         return name;
    14     }
    15     public void setName(String name) {
    16         this.name = name;
    17     }
    18     public String getDepartment() {
    19         return department;
    20     }
    21     public void setDepartment(String department) {
    22         this.department = department;
    23     }
    24     public Cook() {
    25         super();
    26     }
    27     public Cook(String name, String department) {
    28         super();
    29         this.name = name;
    30         this.department = department;
    31     }
    32     @Override
    33     public void Work() {
    34         System.out.println(this.getName()+" 正在工作中......");
    35         
    36     }
    37     
    38 }
    Cook.java 文件内容
     1 /*
     2 @author :yinzhengjie
     3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
     4 EMAIL:y1053419035@qq.com
     5 */
     6 
     7 package cn.org.yinzhengjie.note;
     8 
     9 public class LobbyManager extends Employee {
    10     private String name;
    11     private String department;
    12     private double bonus;
    13     public LobbyManager() {
    14         super();
    15     }
    16     public LobbyManager(String name, String department, double bonus) {
    17         super();
    18         this.name = name;
    19         this.department = department;
    20         this.bonus = bonus;
    21     }
    22     public String getName() {
    23         return name;
    24     }
    25     public void setName(String name) {
    26         this.name = name;
    27     }
    28     public String getDepartment() {
    29         return department;
    30     }
    31     public void setDepartment(String department) {
    32         this.department = department;
    33     }
    34     public double getBonus() {
    35         return bonus;
    36     }
    37     public void setBonus(double bonus) {
    38         this.bonus = bonus;
    39     }
    40     @Override
    41     public void Work() {
    42         System.out.println(this.getName()+" 正在工作中......");
    43     }
    44 
    45 }
    LobbyManager.java 文件内容
     1 /*
     2 @author :yinzhengjie
     3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
     4 EMAIL:y1053419035@qq.com
     5 */
     6 
     7 package cn.org.yinzhengjie.note;
     8 
     9 import java.util.ArrayList;
    10 import java.util.Iterator;
    11 
    12 public class GenericDemo {
    13     public static void main(String[] args) {
    14         //创建三个集合对象
    15         ArrayList<Cook> cook = new ArrayList<>();
    16         ArrayList<Waiter> waiter = new ArrayList<>();
    17         ArrayList<LobbyManager> manager = new ArrayList<>();
    18         
    19         //每个集合都存储自己的元素
    20         cook.add(new Cook("邓西西","主厨001"));
    21         cook.add(new Cook("方合意","主厨002"));
    22         
    23         waiter.add(new Waiter("陶涛","服务部门001"));
    24         waiter.add(new Waiter("邓西","服务部门002"));
    25         
    26         manager.add(new LobbyManager("桂阳","董事会",12463125247.28));
    27         manager.add(new LobbyManager("李洋","董事会",12463125247.28));
    28         iterator(cook);
    29         iterator(waiter);
    30         iterator(manager);
    31         
    32     }
    33     //上限限定,可以传递Employee以及传递他的子类对象。
    34     public static void iterator(ArrayList<? extends Employee> array) {
    35         Iterator<? extends Employee> it = array.iterator();
    36         while(it.hasNext()) {
    37             //获取出来的it.next()的数据类型是Employee,因为我们并不知道它传入的是什么类型的子类。
    38             Employee e = it.next();
    39             e.Work();
    40         }
    41     }
    42 }
    43 
    44 
    45 
    46 /*
    47 以上代码执行结果如下:
    48 邓西西 正在工作中......
    49 方合意 正在工作中......
    50 陶涛 正在工作中......
    51 邓西 正在工作中......
    52 桂阳 正在工作中......
    53 李洋 正在工作中......
    54 */
  • 相关阅读:
    PipedInputStream
    jmeter学习网址
    inside the cpp object model
    AVA中,关键字final癿作用
    静态类
    C#核心概念装箱和拆箱(什么是装箱和拆箱)
    wp7.1 本地数据库 MSDN几篇参考资料
    启动器和选择器学习(6)Extras <wp7 7.1版本中的使用方法>
    启动器和选择器学习(5)启动器
    UI控件分类
  • 原文地址:https://www.cnblogs.com/yinzhengjie/p/8923342.html
Copyright © 2020-2023  润新知