JAVA之旅(二十一)——泛型的概述以及使用,泛型类,泛型方法,静态泛型方法,泛型接口,泛型限定,通配符

释放双眼,带上耳机,听听看~!

JAVA之旅(二十一)——泛型的概述以及使用,泛型类,泛型方法,静态泛型方法,泛型接口,泛型限定,通配符


不知不觉JAVA之旅已经写到21篇了,不得不感叹当初自己坚持要重学一遍JAVA的信念,中途也算是非常的痛苦吧,不过熬到现在,已经算是有点效果了,继续加油,估计三十来篇就能结束自己的JAVA之旅了,go,go!

一.泛型的概述

什么是泛型,我们可以用一个很典型的例子来说明


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
1package com.lgl.hellojava;
2
3import java.util.ArrayList;
4import java.util.Iterator;
5
6//公共的   类   类名
7public class HelloJJAVA {
8    public static void main(String[] args) {
9        /**
10         * 泛型
11         */
12        ArrayList al = new ArrayList();
13        al.add("hello 1");
14        al.add("hello 02");
15        al.add("hello 0300");
16        al.add("hello 084");
17        //添加int
18        al.add(5);
19        Iterator iterator = al.iterator();
20        while (iterator.hasNext()) {
21            String s = (String) iterator.next();
22            // 打印长度
23            sop(s.length());
24        }
25    }
26
27    // 输出
28    public static void sop(Object obj) {
29        System.out.println(obj);
30
31    }
32}
33
34

这里,我们用一个arraylist存储的数据有String也有int,输出的结果

不会发现,他报的就是类型的异常,我们要怎么去解决?这里就牵扯出泛型来了

  • 泛型:JDK1.5版本之后出现的新特性,用于解决安全问题,是一个安全机制;

我们要怎么使用?


1
2
1ArrayList<String> al = new ArrayList<String>();
2

我定义了一个容器,容器的参数是String类型,规范了数据类型,就不能存其他的数据了,安全性提高了!

  • 好处:讲运行时期出现的问题转移到了编译时期,方便程序员解决问题,让运行时期问题减少,安全

二.泛型的使用

泛型的格式:通过<>来定义要操作的引用数据类型,在使用JAVA提供的对象时,什么时候写泛型呢,通常在集合框架中很常见,只要见到<>就是定义泛型!

其实<>就是用来接收类型的,当使用集合时,将集合中要存储的数据类型,作为参数,传递到<>一样 ,我们来个小例子


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
1package com.lgl.hellojava;
2
3import java.util.Comparator;
4import java.util.Iterator;
5import java.util.TreeSet;
6
7//公共的   类   类名
8public class HelloJJAVA {
9    public static void main(String[] args) {
10        TreeSet&lt;String&gt; tr = new TreeSet&lt;String&gt;(new LenComp());
11        tr.add(&quot;hello 01&quot;);
12        tr.add(&quot;hello 012&quot;);
13        tr.add(&quot;hello 013&quot;);
14        tr.add(&quot;hello 014&quot;);
15
16        Iterator&lt;String&gt; iterator = tr.iterator();
17        while (iterator.hasNext()) {
18            String string = iterator.next();
19            sop(string);
20        }
21    }
22
23    // 输出
24    public static void sop(Object obj) {
25        System.out.println(obj);
26
27    }
28}
29
30// 比较器
31class LenComp implements Comparator&lt;String&gt; {
32
33    @Override
34    public int compare(String o1, String o2) {
35        String s1 = o1;
36        int num = new Integer(o1.length()).compareTo(new Integer(o2.length()));
37        if (num == 0) {
38            return o1.compareTo(o2);
39        }
40        return num;
41    }
42
43}
44

你可以仔细的看看里面是怎么用泛型的,就是一些小技巧

三.泛型类

这是我们优化代码比较常见的一种方式,我们可以看这块代码


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
1package com.lgl.hellojava;
2
3//公共的   类   类名
4public class HelloJJAVA {
5    public static void main(String[] args) {
6        Tool t = new Tool();
7        t.setW(new Worker());
8        t.getW();
9    }
10
11    // 输出
12    public static void sop(Object obj) {
13        System.out.println(obj);
14
15    }
16}
17//操作工人的工具类
18class Tool {
19    private Worker w;
20
21    public Worker getW() {
22        return w;
23    }
24
25    public void setW(Worker w) {
26        this.w = w;
27    }
28
29}
30
31class Worker {
32
33}
34
35
36

这里,有一个工人的类,我们定义一个工具类去操作,对吧,这个逻辑就是这么的简单,但是你回发现,如果我在定义一个学生的类,就又得需要一个学生的工具类了,我们为什么不去合并这个工具类,抽调共有的方法呢?你会说可以用Object?


1
2
3
4
5
6
7
8
9
10
11
12
13
14
1//操作工人的工具类
2class Tool {
3    private Object obj;
4
5    public Object getObj() {
6        return obj;
7    }
8
9    public void setObj(Object obj) {
10        this.obj = obj;
11    }
12
13}
14

这样的话,你如果传递的话,还是要定义床底类型,不然会报类型异常的,我们泛型的用法


1
2
3
4
5
6
7
8
9
10
11
12
13
1class Utils&lt;T&gt; {
2
3    private T t;
4
5    public T getT() {
6        return t;
7    }
8
9    public void setT(T t) {
10        this.t = t;
11    }
12}
13

由你来指定传递进来的参数,这样就可以为所欲为了

  • 什么时候定义泛型类

当类中要操作的引用数据类型不确定的时候,早起定义Object来完成扩展,现在定义泛型来完成扩展

四.泛型方法

泛型除了定义在类中,还是可以定义在方法上的,我们来看一下


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
1package com.lgl.hellojava;
2
3//公共的   类   类名
4public class HelloJJAVA {
5    public static void main(String[] args) {
6        Demo&lt;String&gt; d = new Demo&lt;String&gt;();
7        d.show(&quot;hh&quot;);
8        d.print(&quot;aa&quot;);
9    }
10}
11
12class Demo&lt;T&gt; {
13    public void show(T t) {
14        System.out.println(&quot;show:&quot; + t);
15    }
16
17    public void print(T t) {
18        System.out.println(&quot;print:&quot; + t);
19    }
20}
21

泛型类定义的泛型,在整个类中有效,如果被方面使用,那么泛型类的对象明确要操作的具体类型后,所有要操作的类型就已经固定了。

  • 为了让不同的方法可以操作不同的类型,而且类型不确定,那么可以将泛型定义在方法上

仔细看


1
2
3
4
5
6
7
8
9
1class Demo {
2    public &lt;T&gt; void show(T t) {
3
4    }
5    public &lt;T&gt;void print(T t){
6
7    }
8}
9

这样就可以传递泛型参数了

五.静态泛型方法

这个倒不是什么大知识点,就是注意一下,泛型方法不能使用静态的,也可以说静态方法不可以访问类上定义的泛型,如果静态方法操作的应用数据类型不确定,可以将泛型定义在方法上,就可以了


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1
2class Demo&lt;T&gt; {
3    public &lt;T&gt; void show(T t) {
4
5    }
6
7    public &lt;T&gt; void print(T t) {
8
9    }
10
11    public static &lt;T&gt; void method(T t) {
12
13    }
14}
15

要放在static后面哦!

六.泛型接口

你类和方法都有了,怎么能少得了接口呢?


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
1package com.lgl.hellojava;
2
3
4//公共的   类   类名
5public class HelloJJAVA {
6    public static void main(String[] args) {
7        InterImpl&lt;Integer&gt; i = new InterImpl&lt;Integer&gt;();
8        i.show(55);
9    }
10}
11
12class InterImpl&lt;T&gt; implements Inter&lt;T&gt; {
13
14    @Override
15    public void show(T t) {
16        System.out.println(&quot;show:&quot; + t);
17    }
18
19}
20
21interface Inter&lt;T&gt; {
22    void show(T t);
23}
24
25

结构也差不多,传参数就行,但是这种情况是不多见的

七.泛型限定

我们来玩玩泛型的高级用法,go
先从例子切入正题


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
1package com.lgl.hellojava;
2
3import java.util.ArrayList;
4import java.util.Iterator;
5
6//公共的   类   类名
7public class HelloJJAVA {
8    public static void main(String[] args) {
9        ArrayList&lt;String&gt; al = new ArrayList&lt;String&gt;();
10
11        al.add(&quot;hello 01&quot;);
12        al.add(&quot;hello 02&quot;);
13        al.add(&quot;hello 03&quot;);
14        al.add(&quot;hello 04&quot;);
15
16        ArrayList&lt;Integer&gt; all = new ArrayList&lt;Integer&gt;();
17        all.add(9);
18        all.add(596);
19        all.add(98);
20        all.add(97);
21
22        printColl(all);
23    }
24    //内容不明确
25    public static void printColl(ArrayList&lt;?&gt; als) {
26        Iterator&lt;?&gt; iterator = als.iterator();
27        while (iterator.hasNext()) {
28            System.out.println(iterator.next());
29        }
30    }
31}
32
33

问号是占位符,上面的逻辑就是我们有两个arrayList,但是我们需要公用一个方法,内容不明确,所以用问号占位,其实实现的方式还有很多种,还有一种需求使用不到?的,因为?是打印任何的数据,但是我只需要打印限定的几种类型,这个时候该怎么做?


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
1package com.lgl.hellojava;
2
3import java.util.ArrayList;
4import java.util.Iterator;
5
6//公共的   类   类名
7public class HelloJJAVA {
8
9    public static void main(String[] args) {
10        ArrayList&lt;Person&gt; al = new ArrayList&lt;Person&gt;();
11        al.add(new Person(&quot;zhangsan&quot;));
12        al.add(new Person(&quot;lisi&quot;));
13        al.add(new Person(&quot;wangwu&quot;));
14
15        ArrayList&lt;Student&gt; al1 = new ArrayList&lt;Student&gt;();
16        al1.add(new Student(&quot;zhangsan -- 1&quot;));
17        al1.add(new Student(&quot;lisi -- 2&quot;));
18        al1.add(new Student(&quot;wangwu -- 3&quot;));
19
20        // ArrayList
21        printColl(al1);
22    }
23
24    // 内容不明确
25    public static void printColl(ArrayList&lt;? extends Person&gt; als) {
26        Iterator&lt;? extends Person&gt; iterator = als.iterator();
27        while (iterator.hasNext()) {
28            System.out.println(iterator.next().getName());
29        }
30    }
31}
32
33class Person {
34    private String name;
35
36    public Person(String name) {
37        this.name = name;
38    }
39
40    public String getName() {
41        return name;
42    }
43
44    public void setName(String name) {
45        this.name = name;
46    }
47}
48
49class Student extends Person {
50
51    public Student(String name) {
52        super(name);
53    }
54}
55

这里,就能打印出学生和人类,而不打印其他类型的参数了,这就叫泛型限定

  • ?叫通配符,也可以理解为占位符

  • 泛型的限定 ? extends E:E类型和E的子类型。这叫上限

    • ? super E:可以接受E类型和E的父类,这叫下限

下限我就不演示了,有机会的同学可以自己试试看,还是挺好玩的

好的,我们本篇文章就到这里OK了,下一篇聊聊Map吧,恩,下篇再见

欢迎加群:555974449

给TA打赏
共{{data.count}}人
人已打赏
安全技术

详解Node.js API系列 Crypto加密模块(2) Hmac

2021-12-21 16:36:11

安全技术

从零搭建自己的SpringBoot后台框架(二十三)

2022-1-12 12:36:11

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索