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 */
原文地址:https://www.cnblogs.com/yinzhengjie/p/8923342.html