了解的Java泛型

news2024/9/26 5:20:35

作者:~小明学编程  

文章专栏:JavaSE基础

格言:目之所及皆为回忆,心之所想皆为过往
在这里插入图片描述

目录

前言

什么是泛型

为什么要引入泛型

使用泛型

裸类型

泛型类的定义

类型擦除

通配符

什么是通配符

通配符的上下界

通配符的使用

泛型中的父子类


前言

今天给大家带来的文章是Java中的泛型,对于泛型的学习主要是为了让我们能够去阅读Java中的底层源码。

什么是泛型

为什么要引入泛型

 我们随意的点开了我们ArrayList的源码我们就可以看到形如ArrayList<E>的这种写法,我们可以把我们的数据类型当作参数传递给我们的类中,这样我们new对象的时候就比较的灵活了,就不会拘泥于一种类型了。

例如:

        ArrayList<Integer> arrayList1 = new ArrayList<>();
        ArrayList<String> arrayList2 = new ArrayList<>();

因为我们有泛型所以我们的ArrayList才能操作我们不同的数据类型,否则的话只能我们的ArrayList的类就只能操作一种类型,这样的话就很鸡肋,不够灵活。

使用泛型

class MyArray<T> {
    public T[] object = (T[])new Object[10];
    public void set(int pos,T val) {
        this.object[pos] = val;
    }

    public T get(int pos) {
        return object[pos];
    }
}

这里我们自己定义了一个泛型的类里面有一个数组和两个方法。

    public static void main(String[] args) {
        MyArray<String> myArray = new MyArray<>();
        myArray.set(1,"haha");
        String str = myArray.get(1);//这里自动的帮我们将Object的类型转换为String
        System.out.println(str);
    }

然后我们new了一个对象,我们传入一个String类型,然后将我们数组中的1的下标给设置为"haha"。

public T[] object = (T[])new Object[10];

对于这行代码,写的其实不是很好但是基本实现了我们想要表达的东西,因为我们是Object类型的,所以这里要强转为我们的泛型的类型。

裸类型

前面说到泛型,那么与之对应的就是我们的裸类型

MyArray myArray = new MyArray();

裸类型就是在我们new一个对象的时候不给它传递我们的数据类型,这就会导致我们下面的问题

    public static void main(String[] args) {
        MyArray myArray = new MyArray();
        myArray.set(0,13);
        myArray.set(1,"haha");
        String str = (String) myArray.get(1);//这里我们必须进行一个强制类型的转换才能接受
        System.out.println(str);
    }

因为我们没有传递我们的数据类型,所以在我呢吧返回我们对象里面的数据的时候其实都是Object类型的,所以我们这里要进行一个强制类型的转换。

注意: 我们不要自己去使用裸类型,裸类型是为了兼容老版本的 API 保留的机制。

泛型类的定义

上面我们说到泛型可以传入我们的数据类型,但是有时候不是什么类型都能传入的,这个时候就需要我们传入的类型进行一个约束了。

语法

class 泛型类名称<类型形参 extends 类型边界> {

}

其中类型边界表示我们的泛型类可以接受的类型参数的最高的父类。

示例

class C {

}
class D extends C{

}
class E extends D {

}
class Demo<T extends D> {

}

这里我们创建了四个类,其中我们的E继承了D,然后D继承C,然后我们的Demo类接受一个泛型的参数,参数的最高级别为D类,所以

 上面这幅图可以清楚的看到我们最高可以接受的参数类型为D类,然而我们的C是我们D的父类,所以这里就给报错了。

提醒

当我们没有指定我们的上界的时候例如

class MyArray<T>

这时候就默认我们的上界为Object,此时我们可以传入任何的类型,同时也正是因为这个原因,所以我们才需要对其上界进行一个限制。

类型擦除

这里我们有必要说的一点就是泛型是作用在编译期间的一种机制,在我们代码的运行期间实际上是没有这么多的类型的,那么到底我们传入的T在运行的时候是什么类型呢?
   实际上我们运行期间的类型主要取决于我们的边界。

class MyArray<T> {
    public T[] object = (T[])new Object[10];
    public void set(int pos,T val) {
        this.object[pos] = val;
    }

    public T get(int pos) {
        return object[pos];
    }
}

例如我们前面的这个代码我们前面说过没指定边界的话,就默认为Object,所以在代码的运行过程中我们的T就变成了Object。

class Demo<T extends D> {

}

再如上面的这段代码,在我们代码运行的过程中,我们的T就是我们的边界D类型,即使我们传入的参数是C也一样。

这就是我们的类型擦除,也就是在我们运行的时候我们所传的参数类型会被替换为我们的类型上界,同时这个过程是发生在我们的编译期间的。

我们想要实现这样一个功能,有一个类然后类里面有一个方法可以求出我们不同类型数组的的最大值。

写法一:

class Ale<T extends Comparable<T>> {
    public T getMax(T[] array) {
        T max = array[0];
        for (int i = 0; i < array.length; i++) {
            if (max.compareTo(array[i])<0) {
                max = array[i];
            }
        }
        return max;
    }
}

写法一是这样的,我们的T的上界是Comparable,为什么上界要写成这样呢?因为我们下面要对数组里面的元素进行一个比较,如果我们没有Comparable的话我们进行完类型擦除,T将会替换为Object,此时里面没有compareTo方法,无法进行比较。

    public static void main(String[] args) {
        Ale<Integer> ale = new Ale<>();
        System.out.println(ale);
        Integer[] array = {9,3,2,65,34,77,457};
        Integer a = ale.getMax(array);
        System.out.println(a);
        System.out.println(Ale1.getMax(array));
    }

写法二:

class Ale1 {
    public static<T extends Comparable<T>> T getMax(T[] array) {
        T max = array[0];
        for (int i = 0; i < array.length; i++) {
            if (max.compareTo(array[i])<0) {
                max = array[i];
            }
        }
        return max;
    }
}

第二种就是在我们的静态方法中使用泛型。

通配符

什么是通配符

 我们的源码中有很多形如上图的情况问号(?)是什么东西?

问号就是我们Java泛型中的通配符,

class Ale4 {
    public static void print2(ArrayList<?> list) {
        for (Object x:list) {
            System.out.println(x);
        }
    }
}

形如上面这段代码,当我们传参的时候不知道传入什么的时候我们可以使用通配符?,这样我们就可以接受任何泛型类型的参数了。

class Ale3 {
    public static<T> void print1(ArrayList<T> list) {
        for (T x:list) {
            System.out.println(x);
        }
    }
}

当然像上面这样不用通配符写也是能够实现我们上述的功能的。

通配符的上下界

上界的写法

<? extends 上界>

上界表示我们传入的类型最高只能是上界,上界的父类就不能传了。

下界的写法

<? super 下界>

下界表示我们传入的数据类型最低要求是下界,或者下界的父类

首先先来看看我们的上界的用法,

class Ale4 {
    public static void print2(ArrayList<? extends Number> list) {
        for (Object x:list) {
            System.out.println(x);
        }
    }
}

我们通配符和泛型的参数类型一样可以接受上界以内的任何的参数类型,但是我们的泛型会被替换为具体的上界类型而我们的通配符则是对所有对象都适用。

通配符的使用

public static void main10(String[] args) {
        ArrayList<? super Number> arrayList = new ArrayList<>();
        arrayList.add(new Integer(12));
    }

我么的下界适合添加数据,因为因为最低都是Number那么作为我们Number的子类,肯定是能够添加进去的。

    public static void main10(String[] args) {
        ArrayList<? extends Number> arrayList1 = new ArrayList<>();
        arrayList1.get(0);
    }

上界比较适合读入数据,因为我们返回的起码是Number,只要接受类型大于Number就行了。

泛型中的父子类

泛型中的父子类是根据我们通配符来决定的,例如


 MyArrayList<?> 是 MyArrayList<? extends Number> 的父类型
 MyArrayList<? extends Number> 是 MyArrayList<Integer> 的父类型

那么我们就可以写出如下的代码

    public static void main(String[] args) {
        MyArray<Integer> myArray1 = new MyArray<>();
        MyArray<? extends Number> myArray = myArray1;
    }

因为我们的MyArrayList<? extends Number> 是 MyArrayList<Integer> 的父类型所以我们的myArray可以直接引用我们的myArray1。

最后:

这是个人对Java泛型的一些理解,对于泛型的学习可以不用学的很深,只要能看的懂我们的源码就行了,自己写代码的时候就更不要设计到泛型了,除非自己去设计jdk。

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

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

相关文章

Cookie和Session的工作流程以及Servlet中与之相关的API

目录 一、认识Cookie和Session 1、Cookie 2、Session 二、Cookie和Session的工作流程 三、Servlet中与Cookie和Session相关的API 1、HttpServletRequest类中的相关方法 2、HttpServletResponse类中的相关方法 3、HttpSession类中的相关方法 4、Cookie类中的相关方法 …

常用的框架技术-10 Spring Security Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录1.Spring Security简介1.1 Spring Security概述1.2 Spring Security历史发展1.3 产品的对比1.3.1 Spring Security1.3.2 Shiro1.4 Spring Security 核心类1.4.1 Auth…

既然有了ES,为何还用ClickHouse——从原理万字总结ClickHouse为何这么快

通过了解 CH 的几大特性了解千亿级企业 ClickHouse 实时处理引擎架构设计、核心技术设计、运行机理全流程。 文章目录1 初始 ClickHouse1.1 什么是 ClickHouse1.2 ClickHouse 的优缺点1.3 谁在用 ClickHouse3 数据引擎3.1 库引擎3.2 表引擎3.3 MergeTree 引擎4 工作原理4.1 数据…

浙大MBA经验分享:在工作生活的缝隙中奋勇上岸

非常高兴可以为大家分享我的浙大MBA备考经验&#xff01;首先针对我的背景简要介绍一下&#xff0c;我本科毕业于省内的普通大学浙江理工大学&#xff0c;学的是设计专业&#xff0c;就业于一家外企公司。在2022年的联考中获得了综合133&#xff0c;英语75&#xff0c;总分是20…

一个简单的音乐网站设计与实现(HTML+CSS)

⛵ 源码获取 文末联系 ✈ Web前端开发技术 描述 网页设计题材&#xff0c;DIVCSS 布局制作,HTMLCSS网页设计期末课程大作业 | 音乐网页设计 | 仿网易云音乐 | 各大音乐官网网页 | 明星音乐演唱会主题 | 爵士乐音乐 | 民族音乐 | 等网站的设计与制作 | HTML期末大学生网页设计作…

常见集群算法解析

Gossip协议 Gossip协议简介 定义 Gossip protocol&#xff0c;又叫 Epidemic Protocol &#xff08;流行病协议&#xff09;&#xff0c;也叫“流言算法” 、 “疫情传播算法”等。其名称已经形象的说明了算法的原理和工作方式 应用场景 分布式网络&#xff0c;无集中管理节…

同花顺l2数据接口的委托队列是什么?

我们都知道股票交易时有买方也有卖方&#xff0c;“买一”通俗理解就是此刻“买”价最“高”即第一的委托集合&#xff0c;卖一则是“卖”价最低的委托集合。 “一”并非指一笔委托或一手股票&#xff0c;它的背后是有多笔报价相同的买入或卖出委托组成&#xff0c;可能是主力…

cesium火箭发射,模型控制,模型动画,模型移动

起因&#xff1a;最近想做模型的动画&#xff0c;结果上网查资料&#xff0c;看到网上好多对于模型控制的文章都有限制。决定还是自己研究下。欢迎大家一起探讨&#xff0c;评论留言。 效果 火箭全部代码在最后 起步 模型控制&#xff0c;第一步当然是需要一个合适的模型&#…

链动2+1模式是否合法合规?它涉及多级传销吗?

根据国家《禁止传销条例》第2条规定&#xff0c;传销是指组织者或者经营者发展人员&#xff0c;通过对被发展人员以其直接或者间接发展的人员数量或者销售业绩为依据计算和给付报酬&#xff0c;或者要求被发展人员以交纳一定费用为条件取得加入资格等方式牟取非法利益&#xff…

【多线程】Thread的interrupt()

一、前言 如果子线程执行完毕终止状态&#xff0c;主线程再去调用interrupt()有什么效果&#xff1f;如果子线程还在执行过程中&#xff0c;主线程调用interrupt()有什么结果&#xff1f; 二、模拟实验 1、模拟子线程执行完毕再调用interrupt() ​ public class Test {publi…

2023年天津美术学院专升本报名考试须知

天津美术学院2023年高职升本科报考须知&#xff08;一&#xff09;专业考试1.报名方法&#xff1a; ①网上报名及缴费&#xff1a; 我校采取网上报名的方式,考生于2022年12月份&#xff08;具体时间关注公众号“高职接本科”另行公告&#xff09;(10:00-22:00)登录网站(网址&am…

web前端期末大作业 html+css学生心理 7页主题网页设计

⛵ 源码获取 文末联系 ✈ Web前端开发技术 描述 网页设计题材&#xff0c;DIVCSS 布局制作,HTMLCSS网页设计期末课程大作业 | 家 | HTML期末大学生网页设计作业 HTML&#xff1a;结构 CSS&#xff1a;样式 在操作方面上运用了html5和css3&#xff0c; 采用了divcss结构、表单、…

Oculus Deeplink

DeepLink 初始化 platform sdk 后设置 应用启动回调判断应用打开的方式发起应用跳转 接收应用跳转 GroupPresence 本文档基于 GroupPresenceSample 脚本逻辑编写&#xff0c;展示通过群组状态发起用户邀请&#xff0c;以及响应对应回调。参考 Oculus 工程 SharedSpaces 使…

【安装教程】vscode安装教程(超详细)

Visual Studio Code&#xff08;简称 VSCode&#xff09;是一款由微软开发且跨平台的免费源代码编辑器。该软件支持语法高亮、代码自动补全、代码重构功能&#xff0c;并且内置了命令行工具和 Git版本控制系统。用户可以更改主题和键盘快捷方式实现个性化设置&#xff0c;也可以…

想裁剪视频时长,用电脑怎么裁剪视频时长

大家有没有碰到过这种一种情况&#xff0c;就是我们在社交平台上发布视频时&#xff0c;会因为视频时长过长这个问题而导致视频发布失败。那我们要怎么处理这个问题呢&#xff1f;其实我们可以使用一些剪辑软件&#xff0c;将视频裁剪&#xff0c;只截取视频里面较为精彩的部分…

hadoop集群安装(三):创建同步工具并安装jdk

文章目录说明分享环境创建同步工具编写脚本设置为系统命令安装jdk总结说明 搭建好集群虚拟机&#xff0c;新建同步工具并安装jdk&#xff0c;同步工具方便管理集群&#xff0c;某些操作和一条命令&#xff0c;同步所有节点&#xff0c;增加集群操作效率。 分享 大数据博客列表…

组件之间通过bus中央事件总线进行通信

案例完整代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"widt…

66. SAP ABAP Function Module 的动态调用方式使用方式介绍

在本教程前面的步骤 7,我们介绍了 ABAP Function Module 的基本使用方法: 7. ABAP function module 的使用最近我的知识星球有朋友提问: 大佬,我想问一下动态获取到物料主数据的字段名之后,如何将获取到的字段名去与bapi中的字段名对应起来从而去修改物料主数据中对应的字…

多维时序 | MATLAB实现CNN-GRU多变量时间序列预测

多维时序 | MATLAB实现CNN-GRU多变量时间序列预测 目录多维时序 | MATLAB实现CNN-GRU多变量时间序列预测基本介绍模型特点程序设计学习总结参考资料基本介绍 本次运行测试环境MATLAB2020b&#xff0c;MATLAB实现CNN-GRU多变量时间序列预测&#xff0c;卷积门控循环单元。 模型特…

ComponentAce FlexCompress强大功能

ComponentAce FlexCompress强大功能 FlexCompress是一个高速压缩库&#xff0c;旨在为您的应用程序提供归档功能。此解决方案提供了灵活的压缩和强大的加密算法&#xff0c;使您可以快速轻松地将归档或备份功能集成到程序中。 FlexCompress包括我们新的独特技术&#xff0c;即交…