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

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


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

一.泛型的概述

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

package com.lgl.hellojava;

import java.util.ArrayList;
import java.util.Iterator;

//公共的   类   类名
public class HelloJJAVA {
    public static void main(String[] args) {
        /**
         * 泛型
         */
        ArrayList al = new ArrayList();
        al.add("hello 1");
        al.add("hello 02");
        al.add("hello 0300");
        al.add("hello 084");
        //添加int
        al.add(5);
        Iterator iterator = al.iterator();
        while (iterator.hasNext()) {
            String s = (String) iterator.next();
            // 打印长度
            sop(s.length());
        }
    }

    // 输出
    public static void sop(Object obj) {
        System.out.println(obj);

    }
}

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

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

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

我们要怎么使用?

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

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

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

二.泛型的使用

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

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

package com.lgl.hellojava;

import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;

//公共的   类   类名
public class HelloJJAVA {
    public static void main(String[] args) {
        TreeSet<String> tr = new TreeSet<String>(new LenComp());
        tr.add("hello 01");
        tr.add("hello 012");
        tr.add("hello 013");
        tr.add("hello 014");

        Iterator<String> iterator = tr.iterator();
        while (iterator.hasNext()) {
            String string = iterator.next();
            sop(string);
        }
    }

    // 输出
    public static void sop(Object obj) {
        System.out.println(obj);

    }
}

// 比较器
class LenComp implements Comparator<String> {

    @Override
    public int compare(String o1, String o2) {
        String s1 = o1;
        int num = new Integer(o1.length()).compareTo(new Integer(o2.length()));
        if (num == 0) {
            return o1.compareTo(o2);
        }
        return num;
    }

}

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

三.泛型类

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

package com.lgl.hellojava;

//公共的   类   类名
public class HelloJJAVA {
    public static void main(String[] args) {
        Tool t = new Tool();
        t.setW(new Worker());
        t.getW();
    }

    // 输出
    public static void sop(Object obj) {
        System.out.println(obj);

    }
}
//操作工人的工具类
class Tool {
    private Worker w;

    public Worker getW() {
        return w;
    }

    public void setW(Worker w) {
        this.w = w;
    }

}

class Worker {

}

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

//操作工人的工具类
class Tool {
    private Object obj;

    public Object getObj() {
        return obj;
    }

    public void setObj(Object obj) {
        this.obj = obj;
    }

}

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

class Utils<T> {

    private T t;

    public T getT() {
        return t;
    }

    public void setT(T t) {
        this.t = t;
    }
}

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

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

四.泛型方法

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

package com.lgl.hellojava;

//公共的   类   类名
public class HelloJJAVA {
    public static void main(String[] args) {
        Demo<String> d = new Demo<String>();
        d.show("hh");
        d.print("aa");
    }
}

class Demo<T> {
    public void show(T t) {
        System.out.println("show:" + t);
    }

    public void print(T t) {
        System.out.println("print:" + t);
    }
}

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

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

仔细看

class Demo {
    public <T> void show(T t) {

    }
    public <T>void print(T t){

    }
}

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

五.静态泛型方法

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


class Demo<T> {
    public <T> void show(T t) {

    }

    public <T> void print(T t) {

    }

    public static <T> void method(T t) {

    }
}

要放在static后面哦!

六.泛型接口

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

package com.lgl.hellojava;

//公共的   类   类名
public class HelloJJAVA {
    public static void main(String[] args) {
        InterImpl<Integer> i = new InterImpl<Integer>();
        i.show(55);
    }
}

class InterImpl<T> implements Inter<T> {

    @Override
    public void show(T t) {
        System.out.println("show:" + t);
    }

}

interface Inter<T> {
    void show(T t);
}

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

七.泛型限定

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

package com.lgl.hellojava;

import java.util.ArrayList;
import java.util.Iterator;

//公共的   类   类名
public class HelloJJAVA {
    public static void main(String[] args) {
        ArrayList<String> al = new ArrayList<String>();

        al.add("hello 01");
        al.add("hello 02");
        al.add("hello 03");
        al.add("hello 04");

        ArrayList<Integer> all = new ArrayList<Integer>();
        all.add(9);
        all.add(596);
        all.add(98);
        all.add(97);

        printColl(all);
    }
    //内容不明确
    public static void printColl(ArrayList<?> als) {
        Iterator<?> iterator = als.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }
}

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

package com.lgl.hellojava;

import java.util.ArrayList;
import java.util.Iterator;

//公共的   类   类名
public class HelloJJAVA {

    public static void main(String[] args) {
        ArrayList<Person> al = new ArrayList<Person>();
        al.add(new Person("zhangsan"));
        al.add(new Person("lisi"));
        al.add(new Person("wangwu"));

        ArrayList<Student> al1 = new ArrayList<Student>();
        al1.add(new Student("zhangsan -- 1"));
        al1.add(new Student("lisi -- 2"));
        al1.add(new Student("wangwu -- 3"));

        // ArrayList
        printColl(al1);
    }

    // 内容不明确
    public static void printColl(ArrayList<? extends Person> als) {
        Iterator<? extends Person> iterator = als.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next().getName());
        }
    }
}

class Person {
    private String name;

    public Person(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

class Student extends Person {

    public Student(String name) {
        super(name);
    }
}

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

  • ?叫通配符,也可以理解为占位符
    • 泛型的限定 ? extends E:E类型和E的子类型。这叫上限
    • ? super E:可以接受E类型和E的父类,这叫下限

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

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

欢迎加群:555974449

时间: 2024-09-26 20:24:49

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

JAVA之旅(十一)——RuntimeException,异常的总结,Package,jar包,多线程概述

JAVA之旅(十一)--RuntimeException,异常的总结,Package,jar包,多程序概述 继续JAVA之旅 一.RuntimeException 在Exception种有一个特殊的子类异常RuntimeException,翻译过来就是运行异常,如果在函数内容抛出该异常,函数上可以不用声明,编译一样通过,如果在函数上声明了该异常,调用者可以不用处理,编译一样通过 之所以不用函数声明,是因为不需要让调用调用者处理,当然该异常发生,希望程序停止,因为在运行时,出现了无法继续运算的情况

JAVA之旅(三)——数组,堆栈内存结构,静态初始化,遍历,最值,选择/冒泡排序,二维数组,面向对象思想

JAVA之旅(三)--数组,堆栈内存结构,静态初始化,遍历,最值,选择/冒泡排序,二维数组,面向对象思想 我们继续JAVA之旅 一.数组 1.概念 数组就是同一种类型数据的集合,就是一个容器 数组的好处:可以自动给数组中的元素从0开始编号,方便操作这些元素 数组的格式 //公共的 类 类名 public class HelloJJAVA { // 公共的 静态 无返回值 main方法 数组 public static void main(String[] str) { /** * 格式:元素类型

Java设计模式(二十一)----访问者模式

访问者模式 一.概述 1.定义 2.分派的概念 3.分派的类型 4.双重分派 二.结构 三.具体案例 一.概述 1.定义 访问者模式的目的是封装一些施加于某种数据结构元素之上的操作.一旦这些操作需要修改的话,接受这个操作的数据结构则可以保持不变. 2.分派的概念 变量被声明时的类型叫做变量的静态类型(Static Type),有些人又把静态类型叫做明显类型(Apparent Type):而变量所引用的对象的真实类型又叫做变量的实际类型(Actual Type).比如: List list = n

JAVA之旅(三十五)——完结篇,终于把JAVA写完了,真感概呐!

JAVA之旅(三十五)--完结篇,终于把JAVA写完了,真感概呐! 这篇博文只是用来水经验的,写这个系列是因为我自己的java本身也不是特别好,所以重温了一下,但是手比较痒于是就写出了这三十多篇博客了,而且收到的好评也不错,于是就一直坚持了下来,非常感谢各位小伙伴哦! JAVA之旅合集 JAVA之旅(一)--基本常识,JAVA概念,开发工具,关键字/标识符,变量/常量,进制/进制转换,运算符,三元运算 JAVA之旅(二)--if,switch,for,while,do while,语句嵌套,流程

JAVA之旅(二十二)——Map概述,子类对象特点,共性方法,keySet,entrySet,Map小练习

JAVA之旅(二十二)--Map概述,子类对象特点,共性方法,keySet,entrySet,Map小练习 继续坚持下去吧,各位骚年们! 事实上,我们的数据结构,只剩下这个Map的知识点了,平时开发中,也是能看到他的,所以还是非常值得去学习的一个知识点的,我们直接开车了 一.Map概述 泛型< k,v> 键值对,映射关系 基本特点 该集合存储键值对,是一对一对往里存,而且要保证键的唯一性 1.添加 put(key ,values) putAll() 2.删除 clear() remove(ob

JAVA之旅(二十八)——File概述,创建,删除,判断文件存在,创建文件夹,判断是否为文件/文件夹,获取信息,文件列表,文件过滤

JAVA之旅(二十八)--File概述,创建,删除,判断文件存在,创建文件夹,判断是否为文件/文件夹,获取信息,文件列表,文件过滤 我们可以继续了,今天说下File 一.File概述 文件的操作是非常重要的,我们先来看下他的基本概念 用于将文件或者文件夹封装成对象 方便对文件和文件夹的操作 File对象可以作为参数传递给流的构造函数 我们写个小例子先 package com.lgl.hellojava; import java.io.File; public class HelloJJAVA {

JAVA之旅(三十二)——JAVA网络请求,IP地址,TCP/UDP通讯协议概述,Socket,UDP传输,多线程UDP聊天应用

JAVA之旅(三十二)--JAVA网络请求,IP地址,TCP/UDP通讯协议概述,Socket,UDP传输,多线程UDP聊天应用 GUI写到一半电脑系统挂了,也就算了,最多GUI还有一个提示框和实例,我们暂时不讲了,我们直接来重点吧,关于JAVA的网络请求是怎么实现的?当然是HTTP协议,但是不可否认,他的概念和思想都是我们必须去涉及的,包括后面的tcp和socket等,好吧,我们开车吧! 一.JAVA网络请求概述 关于JAVA的网络请求,我们大致的可以分为以下几个分类 网络模式 OSI TCP

JAVA之旅(三十一)——JAVA的图形化界面,GUI布局,Frame,GUI事件监听机制,Action事件,鼠标事件

JAVA之旅(三十一)--JAVA的图形化界面,GUI布局,Frame,GUI事件监听机制,Action事件,鼠标事件 有段时间没有更新JAVA了,我们今天来说一下JAVA中的图形化界面,也就是GUI 一.GUI的概述 GUI全称叫做Graphical User Intergace(图形用户接口),用图形的方式,来显示计算机操作的界面,这样更加方便直观,与用户交互 说道交互,其实系统跟用户有两种交互,一种是GUI,一种叫做CLI,也就是命令行,全称叫做Command User Intergace

JAVA之旅(十七)——StringBuffer的概述,存储,删除,获取,修改,反转,将缓存区的数据存储到数组中,StringBuilder

JAVA之旅(十七)--StringBuffer的概述,存储,删除,获取,修改,反转,将缓存区的数据存储到数组中,StringBuilder 讲完String,我们来聊聊他的小兄弟 一.StringBuffer概述 关于StringBuffer这个对象,Buffer是什么意思?缓冲区的意思,String一旦初始化时不可以被改变的,而StringBuffer是可以的,这就是区别,特点: StringBuffer是一个容器 可以字节操作多个数据类型 最终会通过toString方法变成字符串 存储 S