泛型详解.

news2024/11/19 21:29:09

1 泛型的引入
问题:我们之前实现过的顺序表,只能保存 int 类型的元素,如果现在需要保存 指向 Person 类型对象的引用的顺序表,请问应该如何解决?如果又需要保存指向 Book 对象类型的引用呢?

之前写的顺序表代码示例:

import java.util.Arrays;
 
public class MyArrayList {
    private int[] elem;
    private int usedSize;
    private static int capacity = 10;
 
    public MyArrayList() {
        this.elem = new int[capacity];
    }
 
    public boolean isFull() {
        if (this.usedSize == capacity) {
            return true;
        }
        return false;
    }
 
    public void add(int pos, int data) {
        if (pos < 0 || pos > this.usedSize) {
            System.out.println("pos位置不合法");
            return;
        }
        if (isFull()) {
            this.elem = Arrays.copyOf(this.elem, 2 * capacity);
            capacity *= 2;
        }
        for (int i = this.usedSize - 1; i >= pos; i--) {
            this.elem[i + 1] = this.elem[i];
        }
        this.elem[pos] = data;
        this.usedSize++;
    }
 
    public void display() {
        for (int i = 0; i < this.usedSize; i++) {
            System.out.print(this.elem[i] + " ");
        }
        System.out.println();
    }
 
    public boolean isEmpty() {
        if (this.usedSize == 0) {
            return true;
        }
        return false;
    }
 
    public boolean contains(int toFind) {
        if (isEmpty()) {
            return false;
        }
        for (int i = 0; i < this.usedSize; i++) {
            if (this.elem[i] == toFind) {
                return true;
            }
        }
        return false;
    }
 
    public int search(int toFind) {
        if (isEmpty()) {
            return -1;
        }
        for (int i = 0; i < this.usedSize; i++) {
            if (this.elem[i] == toFind) {
                return i;
            }
        }
        return -1;
    }
 
    public int getPos(int pos) {
        if (isEmpty()) {
            throw new RuntimeException("顺序表为空!");
        }
        if (pos < 0 || pos >= this.usedSize) {
            throw new RuntimeException("pos不合法");
        }
        return this.elem[pos];
    }
 
    public int size() {
        return this.usedSize;
    }
 
    public void setPos(int pos, int value) {
        if (pos < 0 || pos >= this.usedSize) {
            System.out.println("pos位置不合法!");
            return;
        }
        this.elem[pos] = value;
    }
 
    public void remove(int toRemove) {
        if (isEmpty()) {
            return;
        }
 
        int index = search(toRemove);
 
        if (index == -1) {
            System.out.println("没有你要删除的数字!");
        }
 
        for (int i = index; i < this.usedSize - 1; i++) {
            this.elem[i] = this.elem[i + 1];
        }
        this.usedSize--;
    }
 
    public void clear() {
        for (int i = 0; i < this.usedSize; i++) {
            this.elem[i] = 0;
        }
        this.usedSize = 0;
    }
 
 
    public static void main(String[] args) {
        MyArrayList myArrayList = new MyArrayList();
        myArrayList.add(0, 1);
        myArrayList.add(1, 2);
        myArrayList.add(2, 3);
        myArrayList.add(3, 4);
        System.out.println(myArrayList.size());
        myArrayList.display();
        System.out.println(myArrayList.contains(3));
        System.out.println(myArrayList.contains(2));
        System.out.println(myArrayList.search(5));
        System.out.println(myArrayList.search(2));
        System.out.println(myArrayList.getPos(0));
        System.out.println(myArrayList.usedSize);
        myArrayList.display();
        myArrayList.remove(1);
        myArrayList.remove(2);
        myArrayList.display();
        myArrayList.remove(4);
        myArrayList.display();
        myArrayList.clear();
        System.out.println("==============");
        myArrayList.display();
    }
}
  • 首先,我们在学习多态过程中已知一个前提,父类的引用可以指向子类的对象。
  • 其次,我们也已知 Object 是 java 中所有类的祖先类
     

那么,要解决上述问题,我们很自然的想到一个解决办法,将我们的顺序表的元素类型定义成 Object 类型,这样我们的 Object 类型的引用可以指向 Person 类型的对象或者指向 Book 类型的对象了。

因为代码改动较多,现在指出主要代码:

这样,我们可以就可以很自由的存储指向任意类型对象的引用到我们的顺序表了。
 

改编后的代码: 

 

package test1;

import java.util.Arrays;

public class MyArrayList {
    private Object[] elem;
    private int usedSize;
    private static int capacity = 10;

    public MyArrayList() {
        this.elem = new Object[capacity];
    }

    public boolean isFull() {
        if (this.usedSize == capacity) {
            return true;
        }
        return false;
    }

    public void add(int pos, Object data) {
        if (pos < 0 || pos > this.usedSize) {
            System.out.println("pos位置不合法");
            return;
        }
        if (isFull()) {
            this.elem = Arrays.copyOf(this.elem, 2 * capacity);
            capacity *= 2;
        }
        for (int i = this.usedSize - 1; i >= pos; i--) {
            this.elem[i + 1] = this.elem[i];
        }
        this.elem[pos] = data;
        this.usedSize++;
    }

    public void display() {
        for (int i = 0; i < this.usedSize; i++) {
            System.out.print(this.elem[i] + " ");
            System.out.println();
        }
        System.out.println();
    }

    public boolean isEmpty() {
        if (this.usedSize == 0) {
            return true;
        }
        return false;
    }

    public boolean contains(Object toFind) {
        if (isEmpty()) {
            return false;
        }
        for (int i = 0; i < this.usedSize; i++) {
            if (this.elem[i] == toFind) {
                return true;
            }
        }
        return false;
    }

    public int search(Object toFind) {
        if (isEmpty()) {
            return -1;
        }
        for (int i = 0; i < this.usedSize; i++) {
            if (this.elem[i] == toFind) {
                return i;
            }
        }
        return -1;
    }

    public Object getPos(int pos) {
        if (isEmpty()) {
            throw new RuntimeException("顺序表为空!");
        }
        if (pos < 0 || pos >= this.usedSize) {
            throw new RuntimeException("pos不合法");
        }
        return this.elem[pos];
    }

    public int size() {
        return this.usedSize;
    }

    public void setPos(int pos, int value) {
        if (pos < 0 || pos >= this.usedSize) {
            System.out.println("pos位置不合法!");
            return;
        }
        this.elem[pos] = value;
    }

    public void remove(int toRemove) {
        if (isEmpty()) {
            return;
        }

        int index = search(toRemove);

        if (index == -1) {
            System.out.println("没有你要删除的数字!");
        }

        for (int i = index; i < this.usedSize - 1; i++) {
            this.elem[i] = this.elem[i + 1];
        }
        this.usedSize--;
    }

    public void clear() {
        for (int i = 0; i < this.usedSize; i++) {
            this.elem[i] = 0;
        }
        this.usedSize = 0;
    }


    public static void main(String[] args) {
        MyArrayList books = new MyArrayList();
        for (int i = 0; i < 10; i++) {
            books.add(i,new Book("三国演义", "罗贯中", 15));
        }
        books.display();
//        MyArrayList myArrayList = new MyArrayList();
//        myArrayList.add(0, 1);
//        myArrayList.add(1, 2);
//        myArrayList.add(2, 3);
//        myArrayList.add(3, 4);
//        System.out.println(myArrayList.size());
//        myArrayList.display();
//        System.out.println(myArrayList.contains(3));
//        System.out.println(myArrayList.contains(2));
//        System.out.println(myArrayList.search(5));
//        System.out.println(myArrayList.search(2));
//        System.out.println(myArrayList.getPos(0));
//        System.out.println(myArrayList.usedSize);
//        myArrayList.display();
//        myArrayList.remove(1);
//        myArrayList.remove(2);
//        myArrayList.display();
//        myArrayList.remove(4);
//        myArrayList.display();
//        myArrayList.clear();
//        System.out.println("==============");
//        myArrayList.display();
    }
}


遗留问题:现在的 MyArrayList 虽然可以做到添加任意类型的引用到其中了,但遇到以下代码就会产生问题。

写一个Person类:

 接下来我称之为牛马操作:

编译竟然正确,没有报红,我们运行一下看看:

 

运行时会抛出了异常
 

提示:问题暴露的越早,影响越小。编译期间的问题只会让开发者感觉到,运行期间的错误会让所有的软件使用者承受错误风险。

所以我们需要一种机制,可以 1. 增加编译期间的类型检查 2. 取消类型转换的使用 泛型就此诞生!
 

2.泛型的分类

  • 1. 泛型类
  • 2. 泛型方法

3 泛型类的定义的简单演示


 注意: 泛型类可以一次有多个类型变量,用逗号分割。
 

4 泛型背后作用时期和背后的简单原理

  • 1. 泛型是作用在编译期间的一种机制,即运行期间没有泛型的概念。
  • 2. 泛型代码在运行期间,就是我们上面提到的,利用 Object 达到的效果(这里不是很准确,以后会做说明)。
     

5 泛型类的使用


 

通过以上代码,我们可以看到泛型类的一个使用方式:只需要在所有类型后边跟尖括号,并且尖括号内是真正的类型,即 E 可以看作的最后的类型。
 

看具体代码:

package test1;

import java.util.Arrays;

public class MyArrayList<E> {
    private Object[] elem;
    private int usedSize;
    private static int capacity = 10;

    private E e;

    public MyArrayList() {
        this.elem = new Object[capacity];
        this.e = e;
    }

    public boolean isFull() {
        if (this.usedSize == capacity) {
            return true;
        }
        return false;
    }

    public void add(int pos, E data) {
        if (pos < 0 || pos > this.usedSize) {
            System.out.println("pos位置不合法");
            return;
        }
        if (isFull()) {
            this.elem = Arrays.copyOf(this.elem, 2 * capacity);
            capacity *= 2;
        }
        for (int i = this.usedSize - 1; i >= pos; i--) {
            this.elem[i + 1] = this.elem[i];
        }
        this.elem[pos] = data;
        this.usedSize++;
    }

    public void display() {
        for (int i = 0; i < this.usedSize; i++) {
            System.out.print(this.elem[i] + " ");
            System.out.println();
        }
        System.out.println();
    }

    public boolean isEmpty() {
        if (this.usedSize == 0) {
            return true;
        }
        return false;
    }

    public boolean contains(E toFind) {
        if (isEmpty()) {
            return false;
        }
        for (int i = 0; i < this.usedSize; i++) {
            if (this.elem[i] == toFind) {
                return true;
            }
        }
        return false;
    }

    public int search(E toFind) {
        if (isEmpty()) {
            return -1;
        }
        for (int i = 0; i < this.usedSize; i++) {
            if (this.elem[i] == toFind) {
                return i;
            }
        }
        return -1;
    }

    public Object getPos(int pos) {
        if (isEmpty()) {
            throw new RuntimeException("顺序表为空!");
        }
        if (pos < 0 || pos >= this.usedSize) {
            throw new RuntimeException("pos不合法");
        }
        return this.elem[pos];
    }

    public int size() {
        return this.usedSize;
    }

    public void setPos(int pos, int value) {
        if (pos < 0 || pos >= this.usedSize) {
            System.out.println("pos位置不合法!");
            return;
        }
        this.elem[pos] = value;
    }

    public void remove(E toRemove) {
        if (isEmpty()) {
            return;
        }

        int index = search(toRemove);

        if (index == -1) {
            System.out.println("没有你要删除的数字!");
        }

        for (int i = index; i < this.usedSize - 1; i++) {
            this.elem[i] = this.elem[i + 1];
        }
        this.usedSize--;
    }

    public void clear() {
        for (int i = 0; i < this.usedSize; i++) {
            this.elem[i] = 0;
        }
        this.usedSize = 0;
    }


    public static void main(String[] args) {
        MyArrayList<Book> books = new MyArrayList<Book>();
        books.add(0, new Book("红楼梦", "曹雪芹", 18));
        books.add(2, new Person("lisi", "lll"));

//        Book book1 = new Book("红楼梦", "曹雪芹", 18);
//        for (int i = 0; i < 10; i++) {
//            if (i == 0) {
//                books.add(i, book1);
//            } else {
//                books.add(i, new Book("三国演义", "罗贯中", 15));
//            }
//        }
//        books.display();
//        Person person = (Person) books.getPos(0);
//        MyArrayList myArrayList = new MyArrayList();
//        myArrayList.add(0, 1);
//        myArrayList.add(1, 2);
//        myArrayList.add(2, 3);
//        myArrayList.add(3, 4);
//        System.out.println(myArrayList.size());
//        myArrayList.display();
//        System.out.println(myArrayList.contains(3));
//        System.out.println(myArrayList.contains(2));
//        System.out.println(myArrayList.search(5));
//        System.out.println(myArrayList.search(2));
//        System.out.println(myArrayList.getPos(0));
//        System.out.println(myArrayList.usedSize);
//        myArrayList.display();
//        myArrayList.remove(1);
//        myArrayList.remove(2);
//        myArrayList.display();
//        myArrayList.remove(4);
//        myArrayList.display();
//        myArrayList.clear();
//        System.out.println("==============");
//        myArrayList.display();
    }
}

 

那么现在就会出现编译错误 ,这就是泛型的作用!

注意: Book 只能想象成 E 的类型,但实际上 E 的类型还是 Object。
 

6 泛型总结

  • 1. 泛型是为了解决某些容器、算法等代码的通用性而引入,并且能在编译期间做类型检查。
  • 2. 泛型利用的是 Object 是所有类的祖先类,并且父类的引用可以指向子类对象的特定而工作。
  • 3. 泛型是一种编译期间的机制,即 MyArrayList<Person> 和 MyArrayList<Book> 在运行期间是一个类型。
  • 4. 泛型是 java 中的一种合法语法,标志就是尖括号 <>
     

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/388318.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

红黑树-随记

文章目录1.为什么hashmap用红黑树不用二叉树和平衡二叉树1.1 二叉树&#xff08;Binary Search Tree&#xff09;1.2 红黑树&#xff08;Red Black Tree&#xff09;1.3 平衡二叉树&#xff08;Balence Binary Tree&#xff09;也称AVT2.为什么mysql用b数&#xff0c;不用B数或…

Windows程序员学习Linux环境下VI(VIM)编辑器的使用方法

我是荔园微风&#xff0c;作为一名在IT界整整25年的老兵&#xff0c;今天我们来重新审视一下Windows程序员如何学习Linux环境知识。由于很多程序在Windows环境下开发好后&#xff0c;还要部署到Linux服务器上去&#xff0c;所以作为Windows程序员有必要学习Linux环境的知识。VI…

为什么KT6368A双模蓝牙芯片焊到板子上,没反应没收到芯片TX上电返回信息呢

目录 一、问题简介 为什么我把KT6368A芯片焊到板子上面&#xff0c;没有收到芯片TX的脚上电返回信息呢&#xff0c;而KT6368A芯片的2脚一直是2点多v的电压&#xff0c;换了好几个芯片都是这样 二、详细说明 一、问题简介 为什么我把KT6368A芯片焊到板子上面&#xff0c;没有…

QWidgetTable获取选中多行数据

QWidgetTable获取选中的多行数据获取选中行的行编号和打印指定第几列功能快捷键插入链接与图片创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能&#xff0c;丰富你的文章UML 图表FLowchart流…

buu [NPUCTF2020]这是什么觅 1

题目描述&#xff1a; 就一个这种文件&#xff0c;用记事本打开后&#xff1a; 题目分析&#xff1a; 打开后就一串看不懂的东西&#xff0c;想想这个东西曾经在 010editor 或 winhex中出现过&#xff08;右端&#xff09;既然如此那么我们就用它打开&#xff0c;得到&#…

使用 JaCoCo 生成测试覆盖率报告

0、为什么要生成测试覆盖率报告 在我们实际的工作中&#xff0c;当完成程序的开发后&#xff0c;需要提交给测试人员进行测试&#xff0c;经过测试人员测试后&#xff0c;代码才能上线到生产环境。 有个问题是&#xff1a;怎么能证明程序得到了充分的测试&#xff0c;程序中所…

线程池和ThreadLocal详解

线程池和ThreadLocal详解线程池池化模式&#xff1a;线程池里的线程数量设定为多少比较合适?添加线程规则&#xff1a;实现原理&#xff1a;线程池实现任务复用的原理线程池状态&#xff1a;Executors 创线程池工具类手动创建&#xff08;更推荐&#xff09;&#xff1a;自动创…

高码率QPSK调制解调方案(FPGA实现篇)

在前面的章节中,已经讲过QPSK调制的方案和Matlab算法仿真,在本篇中,主要讲解基于FPGA的高速QPSK调制的实现。根据前面提到的技术指标,本系统传输的数据速率为500Mbps,中频为720MHz,因此,传统的串行QPSK调制已经不合适在FPGA中实现,需采用全数字的并行方式进行调制,具体…

电商API是什么?为什么要用?主要应用场景有哪些?

电商API是什么&#xff1f;API是application programming interface&#xff08;应用程序接口&#xff09;的简称&#xff0c;实际上是一些预先定义的函数&#xff0c;目的是提供应用程序与开发人员基于某软件或硬件的以访问一组例程的能力&#xff0c;而又无需访问源码&#x…

强强联合,再强的英伟达NVIDIA也不落俗套

强强联合&#xff0c;全球科技领域永恒的话题【科技明说 &#xff5c; 每日看点】前些天&#xff0c;我看到GPU领域的英伟达(Nvidia)与微软(Microsoft)做了一项十年期的云计算协议&#xff0c;起初我以为微软Microsoft Azure与英伟达GPU方面有所合作&#xff0c;其实不然&#…

微小目标识别研究(1)——白酒杂质识别

文章目录研究项目简介基于机器视觉技术的白酒杂质检测系统研究&#xff08;大概浏览&#xff09;研究背景国内外研究现状和发展趋势国内国外总结白酒杂质检测算法YOLO V3算法K近邻算法滤波处理动态范围增强形态学图像处理运动目标提取数据集制作数据增强基于机器视觉的液体药品…

学习笔记 —— 基于C加速的Python高效计算 (Cython pybind11)

目录引言Cython示例介绍第一阶段优化第二阶段优化Cython Annotation tool优化方法第三阶段优化比对下 JIT的Numba总结pybind11LinksIntroductionImplementationImplementation CmakecytpesCython & pybind11 性能比较TODO Implementation Cmake --pybind11 Cython & py…

Linux SPI 驱动实验

目录 一、Linux 下 SPI 驱动框架简介 1、SPI 主机驱动 2、SPI 设备驱动 SPI 设备数据收发处理流程 3、SPI 设备和驱动匹配过程 二、添加SPI 设备信息 1、添加 ICM20608 所使用的 IO 2、 在 ecspi3 节点追加 icm20608 子节点 三、编写 ICM20608 驱动 1、修改makefile​…

深度学习目标检测ui界面-交通标志检测识别

深度学习目标检测ui界面-交通标志检测识别 为了将算法封装起来&#xff0c;博主尝试了实验pyqt5的上位机界面进行封装&#xff0c;其中遇到了一些坑举给大家避开。这里加载的训练模型参考之前写的博客&#xff1a; 自动驾驶目标检测项目实战(一)—基于深度学习框架yolov的交通…

C++ 二级指针的理解

指针一直很抽象&#xff0c;不是很容易理解&#xff0c;尤其是二级指针。有天路上&#xff0c;脑子里突然想起二级指针&#xff0c;并开始思考什么是二级指针&#xff0c;经过分析和调试验证&#xff0c;对二级指针有了进一步的认识。故写下此篇。 一级指针 假设变量 a、p 的…

消息队列 rabbitmq 学习

RabbitMQ是一个在AMQP基础上完整的&#xff0c;可复用的企业消息系统。他遵循Mozilla Public License开源协议。 MQ全称为Message Queue, 消息队列&#xff08;MQ&#xff09;是一种应用程序对应用程序的通信方法。应用程序通过读写出入队列的消息&#xff08;针对应用程序的数…

[YOLO] yolov4 博客笔记

在有了yolov3的基础上&#xff0c;yolov4的网络结构还是很容易看懂的。 这篇博客写的整个yolov4的网络概况 【经典论文解读】YOLOv4 目标检测https://blog.csdn.net/qq_41204464/article/details/119673960?ops_request_misc%257B%2522request%255Fid%2522%253A%25221677916…

SpringBoot一行代码实现文件上传20个平台!少写代码到极致!

又是做好人好事的一天&#xff0c;有个小可爱私下问我有没有好用的springboot文件上传工具&#xff0c;这不巧了嘛&#xff0c;正好我私藏了一个好东西&#xff0c;顺便给小伙伴们也分享一下&#xff0c;demo地址放在文末了。文件上传在平常不过的一个功能&#xff0c;做后端开…

SpringBoot (三) 整合数据库访问 jdbcTemplate、MyBatis

哈喽&#xff0c;大家好&#xff0c;我是有勇气的牛排&#xff08;全网同名&#xff09;&#x1f42e;&#x1f42e;&#x1f42e; 有问题的小伙伴欢迎在文末评论&#xff0c;点赞、收藏是对我最大的支持&#xff01;&#xff01;&#xff01;。 Spring Data了解下&#xff1…

实习日记_C#——Day2

运算符重载 通过关键字operator后跟运算符的符号来定义。 public static Box operator (Box b, Box c) {Box box new Box();box.height b.height c.height;return box; }Box box1 new Box(1); Box box2 new Box(2); Box box3 new Box(); bo3 box1 box2;接口&#xff…