详解Java中的泛型(泛型的语法,擦除机制,泛型的上界)

news2024/11/27 19:43:59


目录

一.什么是泛型

二.Java中为什么要使用泛型

三.泛型的语法

四.泛型类的使用

五.泛型的编译机制(擦除机制)

六.泛型的上界


一.什么是泛型

泛型(Generics)是Java SE 5中引入的一个新特性,可以使Java中的类和方法具有更广泛的类型范围。通俗的说,它使得我们可以在定义类和方法时指定一个或多个类型参数,从而可以在不考虑具体类型的情况下,代码中直接使用这些类型参数。泛型可以增强代码的安全性、可读性和可重用性。例如,可以使用泛型实现容器类(如ArrayList、HashMap)等。在使用泛型时,需要在编写代码时指定泛型类型,这样可以在编译期间检查代码的类型安全性。

二.Java中为什么要使用泛型

一般的类和方法,只能使用具体的类型::要么是基本类型,要么是自定义的类。如果要编写可以应用于多种类型的代码,这种刻板的限制对代码的束缚就会很大。

----- 来源《Java编程思想》对泛型的介绍

Java中的泛型是一种允许在编写代码时指定类型参数的能力。使用泛型可以使代码更加通用且类型安全。通过使用泛型,程序员可以编写一个方法或类,该方法或类在实例化时可以接受不同类型的参数。泛型是将数据类型参数化,进行传递这样可以减少代码的重复,并提高代码的可读性和可维护性。

假如我们要实现一个数组,使得其中能够存放任意数据类型的元素,想存放整形,又想存放字符型,又想存放引用型该怎么办呢?我们可以联想一下之前认识过的Object类Object类是所有类的父类,那我们将数组置为Object类可以吗?

class MyArray {
    public Object[] array = new Object[10];
    public Object getPos(int pos) {
        return this.array[pos];
    }
    public void setVal(int pos,Object val) {
        this.array[pos] = val;
    }
}
    public static void main(String[] args) {
        MyArray myArray = new MyArray();
        myArray.setVal(0, 10);//整形可以存放
        myArray.setVal(1, "hello");//字符串也可以存放
        String ret = myArray.getPos(1);//编译报错,原因是因为我们数组的类型是Object类型
        //但是我们这里接收的元素却是String类型
        //也就是说我们相当于进行了向下转型,所以这里会报错
        //如果我们进行强制转化就可以解决这个问题
        //String ret = (String) myArray.getPos(1);
        System.out.println(ret);
    }

 我们会发现在这种情况下,整体的语法其实是不灵活的,虽然当前数组任何数据都可以存放,但是更多情况下,我们还是希望他只能够持有一种数据类型,而不是同时持有这么多类型。

所以泛型的主要目的就是指定当前的容器,要持有什么类型的对象,让编译器去做检查。此时就需要把类型作为参数传递需要什么类型,就传入什么类型

三.泛型的语法

在充分认识了泛型的必要性和作用后,我们来看看如何使用它:在Java中,泛型的使用方式是通过在类名或方法名后面加上尖括号,然后在尖括号里指定类型参数。具体语法如下:

class 泛型类名称<类型形参列表> {
    // 这里可以使用类型参数
}
class ClassName<T1, T2, ..., Tn> {
}
class 泛型类名称<类型形参列表> extends 继承类/* 这里可以使用类型参数 */ {
    // 这里可以使用类型参数
}
class ClassName<T1, T2, ..., Tn> extends ParentClass<T1> {
    // 可以只使用部分类型参数
}

可以通过泛型实例化一个泛型对象

泛型类<类型实参> 变量名; // 定义一个泛型类引用
new 泛型类<类型实参>(构造方法实参); // 实例化一个泛型类对象

MyArray<Integer> list = new MyArray<Integer>();

当编译器可以根据上下文推导出类型实参时,可以省略类型实参的填写

MyArray<Integer> list = new MyArray<>(); // 可以推导出实例化需要的类型实参为 Integer

泛型只能接受类,所有的基本数据类型必须使用包装类 

四.泛型类的使用

对于我们刚才的数组,我们就可以如下设置为一个泛型数组

class MyArray<T> {
    public T[] array = (T[])new Object[10];//1
    //public T[] array;
    public T getPos(int pos) {
        return this.array[pos];
    }
    public void setVal(int pos,T val) {
        this.array[pos] = val;
    }
}
    public static void main(String[] args) {
        MyArray<Integer> myArray1 = new MyArray<>();//2
        myArray1.setVal(0,10);
        myArray1.setVal(1,12);
        
        MyArray<String> myArray2 = new MyArray<>();//3
        myArray2.setVal(0,"hello");
        myArray2.setVal(1,"world");
        
        MyArray<Float> myArray3 = new MyArray<>();//4
        myArray3.setVal(0,1.23f);
        myArray3.setVal(1,3.14f);
    }

在上述代码块中

类名后的 <T> 代表占位符,表示当前类是一个泛型类,常用的其他名称有:

  • E 表示 Element
  • K 表示 Key
  • V 表示 Value
  • N 表示 Number
  • T 表示 Type
  • S, U, V 等等... ...

注释1处,不能new泛型类型的数组,也就是说下面这样的代码是错误的

T[] arrary = new T[5];//是不对的

注释2处,类型后加入 <Integer> 指定当前类型,注释3,4处同理

五.泛型的编译机制(擦除机制)

Java的类型擦除机制是指在编译期间将泛型的类型参数替换为其边界或Object类型,从而实现泛型代码运行时无需知晓实际类型参数,也就是说泛型的类型参数在运行时是被擦除了的。这个机制是为了兼容Java语言的旧版本,同时也可以减少代码重复,使得代码更加简洁。

举个例子来说,:

        假如有一个泛型类List<T>,其中的T可以指定任何类型,但是在运行时,List<T>的实际类型是List<Object>。那么,当我们在使用List<T>时,编译器会自动擦除类型参数T,然后将List<T>替换为List<Object>,这样就可以在运行时使用Object类型来处理元素。

        在编译期间,泛型类型参数String被擦除了,List<String>被替换成了List<Object>,而在运行时,get方法返回的是Object类型,需要强制转换为String类型,也就是说,我们无法在运行时获取到类型参数的具体值,因为编译器已经将其擦除了。

泛型到底是如何进行编译的?这曾经作为面试题进行考察过,泛型的语法实际上是非常复杂不容易理解的,我们需要借助他的字节码文件去观察,使用命令:javap -c 查看字节码文件

也就是说在编译的过程当中,将所有的T替换为Object这种机制,我们称为:擦除机制

这个类型擦除机制也给开发带来了一些限制和挑战,比如不能在运行时获取泛型参数的具体类型,泛型数组的创建受到限制等。但是通过一些技巧和设计模式,我们可以在一定程度上绕过这些限制,让代码更加灵活和可扩展。

六.泛型的上界

在定义泛型类时,有时需要对传入的类型变量做一定的约束,可以通过类型边界来约束,语法:

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

例如:

public class MyClass<T extends MyClass2> {
    // ...
}

上述代码中,泛型类型T的上界是MyClass2,这意味着在使用MyClass时,只能传入MyClass2或其子类作为T的实际类型参数。这样做可以确保在类型安全的前提下,使用泛型类型时具有更大的灵活性和可扩展性。

假设我们有一个泛型类Box<T>,我们希望确保这个类型参数T必须是实现了Comparable接口的类。我们可以使用泛型的上界<T extends Comparable<T>>来实现这个目标,示例代码如下:

public class Box<T extends Comparable<T>> {
    private T value;

    public Box(T value) {
        this.value = value;
    }

    public T getValue() {
        return value;
    }

    public boolean isGreaterThan(Box<T> otherBox) {
        return value.compareTo(otherBox.getValue()) > 0;
    }
}

在这个示例中,我们使用<T extends Comparable<T>>来定义类型参数上界,确保T必须是实现了Comparable接口的类。这样,我们就可以在isGreaterThan()方法中使用value.compareTo()方法来比较value字段和另一个Box对象的值了。




  本次的分享就到此为止了,希望我的分享能给您带来帮助,也欢迎大家三连支持,你们的点赞就是博主更新最大的动力!如有不同意见,欢迎评论区积极讨论交流,让我们一起学习进步!有相关问题也可以私信博主,评论区和私信都会认真查看的,我们下次再见

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

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

相关文章

这些steam游戏搬砖知识,你不会还不知道吧?

CSGO搬砖日常出货更新 大家好&#xff0c;我是阿阳&#xff0c;一个只讲项目实操干货的创业博主。今天的内容主要是针对准备踏入游戏行业的新人来讲的&#xff1a; 1、首先大家一定要弄清游戏搬砖到底是哪一个游戏搬砖&#xff0c;因为市面上有个叫游戏打金的很多人也习惯把他…

Liunx系统使用超详细(二)

本篇内容是总结罗列Liunx系统日常使用的基础操作&#xff01;&#xff01;&#xff01; 目录 一、查看IP地址 1.1使用 ip 命令 1.2使用 ifconfig 命令 1.3使用hostname命令&#xff08;仅显示主机名&#xff09; 1.4使用curl命令获取公共IP地址 二、重启网卡(网络接口) …

实在智能荣获36氪消费新势力榜单“优选品牌服务商”

近日&#xff0c;36氪未来消费正式公布「FUTURE 2023」消费新势力名单&#xff0c;实在智能凭借专业的数字化产品力、卓越的服务力和深远的行业影响力&#xff0c;成功入选榜单并获评“优选品牌服务商”。 据悉&#xff0c;此次名单是由36氪未来消费特邀消费领域的行业专家、投…

开源运维监控系统-Nightingale(-夜莺)应用实践(未完)

一、前言 某业务系统因OS改造,原先的Zabbix监控系统推倒后未重建,本来计划用外部企业内其他监控系统接入,后又通知需要自建才能对接,考虑之前zabbix的一些不便,本次计划采用一个类Prometheus的监控系统,镜调研后发现Nightingale兼容Prometheus,又有一些其他功能增强,又…

【微服务】java 规则引擎使用详解

目录 一、什么是规则引擎 1.1 规则引擎概述 1.2 规则引擎执行过程 二、为什么要使用规则引擎 2.1 使用规则引擎的好处 2.1.1 易于维护和更新 2.1.2 增强应用程序的准确性和效率 2.1.3 加快应用程序的开发和部署 2.1.4 支持可视化和可管理性 2.2 规则引擎使用场景 三、…

Python实现FA萤火虫优化算法优化循环神经网络分类模型(LSTM分类算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 萤火虫算法&#xff08;Fire-fly algorithm&#xff0c;FA&#xff09;由剑桥大学Yang于2009年提出 , …

CNN对 MNIST 数据库中的图像进行分类

加载 MNIST 数据库 MNIST 是机器学习领域最著名的数据集之一。 它有 70,000 张手写数字图像 - 下载非常简单 - 图像尺寸为 28x28 - 灰度图 from keras.datasets import mnist# 使用 Keras 导入MNIST 数据库 (X_train, y_train), (X_test, y_test) mnist.load_data()print(&…

防火墙简介

防火墙概念 是指一种将内部网和公众访问网&#xff08;如Internet&#xff09;分开的方法&#xff0c;它实际上是一种建立在现代通信网络技术和信息安全技术基础上的应用性安全技术&#xff0c;隔离技术。 将需要保护的网络和不可信网络进行隔离&#xff0c;隐藏信息并…

【华为OD】统一考试B\C卷真题 100%通过:开源项目热榜 C/C++实现

目录 题目描述&#xff1a; 示例1 示例2 题目描述&#xff1a; 某个开源社区希望将最近热度比较高的开源项目出一个榜单&#xff0c;推荐给社区里面的开发者。对于每个开源项目&#xff0c;开发者可以进行关注(watch)、收藏(star)、fork、提issue、提交合并请求(MR)等。 数…

振南技术干货集:znFAT 硬刚日本的 FATFS 历险记(2)

注解目录 1、znFAT 的起源 1.1 源于论坛 &#xff08;那是一个论坛文化兴盛的年代。网友 DIY SDMP3 播放器激起了我的兴趣。&#xff09; 1.2 硬盘 MP3 推了我一把 &#xff08;“坤哥”的硬盘 MP3 播放器&#xff0c;让我深陷 FAT 文件系统不能自拔。&#xff09; 1.3 我…

spring Cloud在代码中如何应用,erueka 客户端配置 和 服务端配置,Feign 和 Hystrix做高可用配置

文章目录 Eureka一、erueka 客户端配置二、eureka 服务端配置 三、高可用配置FeignHystrix 通过这篇文章来看看spring Cloud在代码中的具体应用&#xff0c;以及配置和注解&#xff1b; Eureka 一、erueka 客户端配置 1、Eureka 启禁用 eureka.client.enabledtrue 2、Eurek…

在Windows上配置MySql开发java,导入JDBC的jar包后连接SQL Server数据库结合Java和MySql的一些简单实践

在Windows上配置MySql 我们先进入MySql官网 在官网中选择MySQL Installer for Windows 进入后选择第一个下载 接下来安装即可&#xff0c;在安装时&#xff0c;可以只安装MySql Server&#xff08;默认选项&#xff09;,选择Full也可&#xff0c;这样会同时安装workbench以及…

智能优化算法应用:基于蜻蜓算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于蜻蜓算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于蜻蜓算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.蜻蜓算法4.实验参数设定5.算法结果6.参考文献7.MATLAB…

SocialFi 和 GameFi 的碰撞 — Socrates 构建新的 Web3 流量入口

伴随着比特币现货 ETF 即将通过 SEC 批准的消息&#xff0c;整个加密市场在11月份达到了熊市以来的新高峰。市场普遍上涨&#xff0c;新的玩法和项目不断涌出吸引了大量老用户回归以及新用户加入。加密市场经过长期的低迷&#xff0c;终于来到了牛市的起点&#xff01; 上一轮牛…

[C++]六大默认成员函数详解

☃️个人主页&#xff1a;fighting小泽 &#x1f338;作者简介&#xff1a;目前正在学习C和Linux &#x1f33c;博客专栏&#xff1a;C入门 &#x1f3f5;️欢迎关注&#xff1a;评论&#x1f44a;&#x1f3fb;点赞&#x1f44d;&#x1f3fb;留言&#x1f4aa;&#x1f3fb; …

1980-2022年世界各国专利、商标申请数据/世界各国知识产权专利申请数据

1980-2022年世界各国专利、商标申请数据/世界各国知识产权专利申请数据 1、时间&#xff1a;1980-2022年 2、来源&#xff1a;WIPO数据库 3、范围&#xff1a;世界各国&#xff08;180多个国家&#xff09; 4、指标&#xff1a;国家名称、年份、代码、类型、专利申请总量、…

老鸟整理,银行测试业务+银行测试案例编写,超细汇总...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 银行的软件测试是…

2023中国SaaS大会完美收官,体验管理开辟SaaS续费增长新曲线

11月17日-19日&#xff0c;2023中国SaaS大会在苏州太湖万豪酒店完美收官。本场专属于SaaS人的行业盛会&#xff0c;设有运动会、实战闭门会、公开课、辩论赛、嘉宾对话及演讲等多项精彩活动&#xff0c;吸引了千余名To B&#xff08;SaaS&#xff09;领域创业者、投资人、企业客…

古埃及金字塔的修建

从理论上说&#xff0c;古埃及人完全有能力设计并建造出充满各种奇妙细节的胡夫金字塔&#xff0c;但后世还是不断涌现出质疑之声&#xff0c;原因倒也简单&#xff0c;那就是胡夫金字塔实在太大了。据推算&#xff0c;整座金字塔使用大约230万块巨石&#xff0c;总质量可达约5…

通俗易懂的spring Cloud;业务场景介绍 二、Spring Cloud核心组件:Eureka 、Feign、Ribbon、Hystrix、zuul

文章目录 通俗易懂的spring Cloud一、业务场景介绍二、Spring Cloud核心组件&#xff1a;Eureka三、Spring Cloud核心组件&#xff1a;Feign四、Spring Cloud核心组件&#xff1a;Ribbon五、Spring Cloud核心组件&#xff1a;Hystrix六、Spring Cloud核心组件&#xff1a;Zuul七…