解析Java中的包装类和泛型

news2024/11/20 1:24:10

Java中的包装类和泛型

  • 一、包装类与基本类型
  • 二、泛型
    • 1、什么是泛型
    • 2、引出泛型
    • 3、泛型类的定义和使用
    • 4、擦除机制
    • 5、泛型的上界
    • 6、泛型方法
    • 7、通配符
  • 总结

一、包装类与基本类型

包装类,就是基本数据类型对应的类类型。我们已知Java中有8种基本数据类型,这些基本数据类型中除了int对应的包装类Integerchar对应的包装类Character其它包装类均为基本类型首字母大写。

装箱/装包: 把基本类型变为对应的包装类型

拆箱/拆包: 将包装类型拆箱为基本数据类型

//装箱/装包:把基本类型变为对应的包装类型
int a=10;
Integer val0 = (Integer)a;//自动装箱
Integer val1 = a;//自动装箱-->底层就是调用的是以下两个方法:

Integer val2 = Integer.valueOf(a);//手动装箱
Integer val3 = new Integer(a);    //手动装箱
		
//拆箱/拆包:将包装类型拆箱为基本数据类型
Integer value1 = 10;//这里存在自动装箱
int z = (int)value1;//自动拆箱
int a = value1;     //自动拆箱-->底层调用了以下方法:
int b = value1.intValue();//手动拆箱
double c = value1.doubleValue();//包装类的权限更大,可以拆成其它类型

一道有坑的面试题:

public static void main(String[] args) {
Integer a = 127;
Integer b = 127;
Integer c = 128;
Integer d = 128;
System.out.println(a == b);
System.out.println(c == d);
}

先说结论,输出结果为 truefalse.其实这道题就考察了装箱的底层原理,我们找到装箱源码:

二、泛型

1、什么是泛型

一般的类和方法,只能使用具体的类型: 要么是基本类型,要么是自定义的类。如果要编写可以应用于多种类型的代码,这种刻板的限制对代码的束缚就会很大。通俗讲,泛型:就是适用于许多许多类型。从代码上讲,就是对类型实现了参数化。

2、引出泛型

需求: 实现一个类,类中包含一个数组成员可以存放任意类型的数据。

根据我们已知的知识,Object类默认为所有类的父类(包括八大基本类型的包装类),所以我们可以创建一个Object类型的数组用来容纳各种类型的数据。具体实现如下:

class MyArrays {
    public Object[] obj = new Object[5];

    public Object getPos(int pos) {
        return obj[pos];
    }

    public void setPos(Object val,int pos) {
        obj[pos] = val;
    }
}

public class TestDemo {
    public static void main(String[] args) {
        MyArrays myArrays = new MyArrays();
        myArrays.setPos(6,0);
        myArrays.setPos("world",1);
        myArrays.setPos(10.5,2);
        int a = (int)myArrays.getPos(0);
        String str = (String)myArrays.getPos(1);
        double d = (double)myArrays.getPos(2);
    }
}

上面的Object数组确实可以实现什么类型的数据都能存储,但是也有一个问题:对于使用者来说,他们可能并不知道Object数组中每个下标存的到底是什么类型的数据,所以这就给使用时带来了麻烦。

结论:

所以更多情况下,我们还是希望他只能够持有一种数据类型,而不是同时持有这么多类型。所以,泛型的主要目的:就是指定当前的容器,要持有什么类型的对象,让编译器去做检查。此时,就需要把类型,作为参数传递,需要什么类型,就传入什么类型。

3、泛型类的定义和使用

泛型语法

			//泛型类的定义
//概念化
class 泛型类名称<类型形参列表> {
	// 这里可以使用类型参数
}//具体化
class ClassName<T1, T2, ..., Tn> {
	// 这里可以使用类型参数
}
			//泛型类的使用
泛型类<类型实参> 变量名 = new 泛型类<类型实参>(构造方法实参); // 实例化一个泛型类对象

按照上述规则,将上面引入改写:

class MyArray<T> {
	// 泛型数组(底层为Object)
    public Object[] obj = new Object[5];

    public void setObj(int pos,T val) {
        obj[pos]=val;
    }
    
    public T getPos(int pos) {
        return (T)obj[pos];
    }
}
//测试
public class TestDemo {
    public static void main1(String[] args) {
        MyArray<Integer> myArray = new MyArray<>();
        //可以推导出实例化需要的类型实参为 Integer,所以这里的<>中内容可省略
        myArray.setObj(0,1);
        myArray.setObj(1,2);
        myArray.setObj(2,3);
        int a = myArray.getPos(0);
        //myArray.setObj(4,"hello");//编译器会对类型检查,导致此处编译报错
    }
}

注解:

  1. 类名后的 < T > 代表占位符,表示当前类是一个泛型类,T是类型形参(引用类型),一般使用一个大写字母表示,常用的名称有:
    (1) E 表示 Element
    (2) K 表示 Key
    (3) V 表示 Value
    (4) N 表示 Number
    (5) T 表示 Type
    (6) S, U, V 等等 - 第二、第三、第四个类型
  2. 测试代码中,类型后加入 < Integer > 指定当前容器类型为Integer.
  3. int a = myArray.getPos(0);不需要进行强制类型转换.
  4. myArray.setObj(4,"hello");编译报错,是因为上面已指定类当前的类型为Integer,编译器会帮我们进行类型检查.
  5. 泛型只能接受类,所有的基本数据类型必须使用包装类!
  6. MyArray<Integer> myArray = new MyArray<>();当编译器可以根据上下文推导出类型实参时,可以省略类型实参的填写.
  7. 错误定义方式T[] ts = new T[5];不能new泛型类型的数组.

4、擦除机制

在编译的过程当中,将所有的T替换为Object这种机制,我们称为:擦除机制。Java的泛型机制是在编译级别实现的。编译器生成的字节码在运行期间并不包含泛型的类型信息。对于泛型的编译这里我们就点到为止,目前先了解泛型有这样一个机制,想要真正理解泛型是需要时间和知识的打磨的!

5、泛型的上界

语法

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

例如:

//代表将来指定的参数E类型一定是实现了Comparable这个接口的
class Alg<E extends Comparable<E>> {

}

//E是Number的子类或者E是Number本身
class Alg2<E extends Number> {

}

使用场景: 实现一个泛型类,包含一个求数组最大值的方法。

分析: 由于类型形参E是一个引用类型,我们知道引用类型数值比较是不能直接使用大于小于号的,而是需要使用compareTo()比较方法,使用此方法又需要实现Comparable接口,而此时如果不使用泛型上界的话,最终E会被擦除为Object导致不能使用compareTo()方法,所以需要使用泛型上界E extends Comparable<E>

class Alg<E extends Comparable<E>> {
	//如果不使用泛型上界会导致E被擦除为Object,后面
    public E findMax(E[] array) {
        E max = array[0];
        for (int i = 1; i < array.length; i++) {
            if (max.compareTo(array[i])<0) {
                max = array[i];
            }
        }
        return max;
    }
}
//测试
public class TestDemo {
    Alg<Integer> alg = new Alg<>();
    Integer[] array = {5,2,7,100,3,6,9};
    int max = alg.findMax(array);
    System.out.println(max);
}

6、泛型方法

语法

方法限定符 [static] <类型形参列表> 返回值类型 方法名称(形参列表) { ... }

使用泛型方法改写上述求最大值泛型类:

class Alg2 {
    //这里将其改写成静态的方法
    public static  <E extends Comparable<E>> E findMax(E[] array) {
        E max = array[0];
        for (int i = 1; i < array.length; i++) {
            if(max.compareTo(array[i])<0) {
                max=array[i];
            }
        }
        return max;
    }
}
//测试
public class TestDemo {
    public static void main(String[] args) {
        Integer[] array1 = {1,2,3,4,5};
        Integer[] array2 = {6,7,8,9,10};
        int max2 = Alg2.<Integer>findMax(array2);
        //可以使用类型推导省略<>
        int max1 = Alg2.findMax(array1);
        System.out.println("array1的最大值为:"+max1);
        System.out.println("array2的最大值为:"+max2);
    }

7、通配符

? 用于在泛型的使用,即为通配符

在"?"的基础上又产生了两个子通配符:

(1)? extends 类:设置通配符上限

<? extends 上界>
<? extends Number>//可以传入的实参类型是Number或者Number的子类

(2)? super 类:设置通配符下限

<? super 下界>
<? super Integer>//代表 可以传入的实参的类型是Integer或者Integer的父类类型

特别注意: 使用 ? 通配符时,无法对泛型类型进行具体化操作,即不能将具体类型赋值给 ?。因此,在使用 ? 通配符的地方,只能进行读取操作(获取或比较),而不能进行写入操作(添加或修改)。这是为了保证类型安全性。

总结

到这里本文就结束了,或许读完本文你对泛型的理解还是萌萌懂懂,不过这都没关系,本篇文章的主要目的是能够对泛型在语法层面有一个基本的认知,想要真正理解泛型是需要时间和知识的打磨的!

到此断断续续的JavaSE也就告一段落了,总的来说Java的语法没有那么多弯弯绕绕,重点在于理解“面向对象”的概念。当然了JavaSE对于整个编程星球来说也只是一块敲门砖。路漫漫其修远兮,吾将上下而求索,我们下期再见喽!

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

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

相关文章

算法与数据结构(二十二)动态规划解题套路框架

动态规划解题套路框架 此文只在个人总结 labuladong 动态规划框架&#xff0c;仅限于学习交流&#xff0c;版权归原作者所有&#xff1b; 动态规划问题&#xff08;Dynamic Programming&#xff09;应该是很多读者头疼的&#xff0c;不过这类问题也是最具有技巧性&#xff0c…

BurpSuite超详细安装教程-功能概述-配置-使用教程---(附下载链接)

一、介绍 BurpSuite是渗透测试、漏洞挖掘以及Web应用程序测试的最佳工具之一&#xff0c;是一款用于攻击web 应用程序的集成攻击测试平台&#xff0c;可以进行抓包、重放、爆破&#xff0c;包含许多工具&#xff0c;能处理对应的HTTP消息、持久性、认证、代理、日志、警报。 二…

港科夜闻|追求卓越教学奖颁奖典礼成功举办,两位香港科大教授获表彰

关注并星标 每周阅读港科夜闻 建立新视野 开启新思维 1、2022年度追求卓越教学奖颁奖典礼于近日成功举办&#xff0c;两位香港科大教授获表彰。香港科大社会科学学部王家礼教授获得“追求卓越教学奖(The Common Core Teaching Excellence Award)”&#xff0c;香港科大公共政策…

Python小白入门:关于函数的超详解知识点总结(定义、传递参数、返回值、模块等)

本文目录 一、定义函数二、传递实参2.1 位置实参2.2 关键字参数2.3 默认值练习题代码输出 三、返回值3.1 返回简单值3.2 可选实参3.3 返回字典3.4 在函数中使用while循环练习题代码输出 四、传递列表4.1 在函数中修改列表4.2 禁止函数修改列表练习题代码输出 五、传递任意数量的…

【Linux】常用的文本处理命令详解 + 实例 [⭐实操常用,建议收藏!!⭐]

&#x1f468;‍&#x1f393;博主简介 &#x1f3c5;云计算领域优质创作者   &#x1f3c5;华为云开发者社区专家博主   &#x1f3c5;阿里云开发者社区专家博主 &#x1f48a;交流社区&#xff1a;运维交流社区 欢迎大家的加入&#xff01; &#x1f40b; 希望大家多多支…

【雕爷学编程】Arduino动手做(195)---HT16k33 矩阵 8*8点阵屏模块6

37款传感器与模块的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&#x…

Positive证书是什么?

Positive SSL是全球著名CA Sectigo的子品牌&#xff0c; 也是目前全球签发量最高的商业SSL证书。价格低&#xff0c;安全性高&#xff0c;在个人网站和中小型企业网站中拥有极高的占有率。 Positive SSL证书包括DV SSL&#xff0c; EV SSL&#xff0c;也是唯一支持IP地址加密的…

Scratch 之 TurboWarp 常用插件介绍-1

今天带来2篇 TurboWarp 常用插件介绍。 什么你还没有 TurboWarp &#xff1f;快去下载一个吧 TurboWarp&#xff08;简称TW&#xff09; 在线版 | 离线版下载 TurboWarp优点 编译速度快于原版 Scratch 至少10倍拥有自定义帧的功能&#xff08;比如60 FPS&#xff09;造型编…

【ppt技巧】PPT限制修改的两种方法

PPT文件制作完成之后&#xff0c;保护PPT文件样式以及内容&#xff0c;很重要&#xff0c;防止生成的模板不被修改也很重要。今天分享两种限制修改PPT文件的方法。 方法一&#xff1a; 想要PPT文件中添加的logo、页脚、标题样式等不被改变&#xff0c;可以将所有设置在幻灯片…

无需公网-用zerotier异地组网

无需公网-用zerotier异地组网 在前面的文章中我们讲到利用frp进行内网穿透&#xff0c;但是他的局限在于你需要一台公网服务器。并且对公网服务器的带宽有一定的要求。因此这里我们推荐一款异地组网工具搭建属于自己的虚拟网络&#xff0c;经过授权连接成功之后彼此都在同一网…

8个电商值得关注的3D模型利用技巧

赛车、咖啡机、能量饮料、餐椅、野营炊具、曲棍球棒、钻戒&#xff0c;甚至风火轮玩具车。 你可以在 Shopify 商店中找到它们&#xff0c;现在借助文件标准和 Web 渲染的最新进展&#xff0c;你可以在自己的笔记本电脑屏幕上以 3D 模型的形式看到这些精确的产品。 更重要的是&a…

apache poi合并单元格 横向竖向合并单元格

合并单元格是常见的需求&#xff0c;apache POI的合并单元格的原理很简单&#xff0c;它就是从左上到右下的单元格会被左上合并&#xff0c;无论是横向合适纵向合并单元格合并&#xff0c;都是这个原理&#xff0c;关键的api方法 org.apache.poi.hssf.model.InternalSheet#add…

分布式链路追踪之SkyWalking详解和实战

SkyWalking 文章目录 SkyWalking1.SkyWalking概述2.SkyWalking架构设计3.SkyWalking部署4.应用程序接入SkyWalking5.SkyWalking配置应用告警5.1.告警规则5.2.Webhook&#xff08;网络钩子&#xff09;5.3.邮件告警实践 6.项目自动化部署接入SkyWalking6.1 整体思路6.2 启动参数…

Python web实战之细说Django的中间件

&#x1f511; 关键词&#xff1a;Python Web 开发、Django、中间件 今天分享Python Web开发中的一个重要成员&#xff1a;Django的中间件。介绍中间件的概念、作用及其在实战中的应用。 1 什么是中间件 在Python Web开发中&#xff0c;中间件&#xff08;Middleware&#xff…

【FAQ】视频监控EasyCVR平台登录密码忘记?如何通过navicat连接数据库进行修改?

TSINGSEE青犀视频监控管理平台EasyCVR可以根据不同的应用场景需求&#xff0c;让平台在内网、专网、VPN、广域网、互联网等各种环境下进行音视频的采集、接入与多端分发。在视频能力上&#xff0c;平台可实现视频实时直播、云端录像、云存储、回放与检索、告警上报、视频快照、…

企业智能制造成熟度报告

《“十四五”智能制造发展规划》明确提出&#xff0c;到2025年&#xff0c;70%的规模以上制造业企业基本实现数字化网络化&#xff0c;智能制造能力成熟度水平明显提升&#xff0c;并指出要建立长效评价机制&#xff0c;鼓励第三方机构开展智能制造能力成熟度评估&#xff0c;研…

LLVM笔记2 Intermediate Representation (IR)

参考链接&#xff1a;https://llvm.org/devmtg/2019-04/slides/Tutorial-Bridgers-LLVM_IR_tutorial.pdf https://zhuanlan.zhihu.com/p/163063995 https://zhuanlan.zhihu.com/p/163328574 文章目录 IR的布局1. IR语法2.IR递归函数3.使用迭代的方式4.全局变量5.LLVM’s type s…

STM32U5系列芯片,不支持ST-LINK v2怎么办

方案一 淘宝 唐卡思 购买stlink V3 &#xff08;万能的淘宝&#xff09; 方案二 使用jlink KEIL版本V5.34以上 支持M33编译 工程的分扇加载SCT件需要修改

LDAP协议

目录 LDAP是什么&#xff1f;什么是目录服务&#xff1f;什么是LDAP认证&#xff1f; 为什么要用LDAP&#xff1f;LDAP能做什么&#xff1f;为什么用LDAP做身份验证&#xff1f;LDAP的产品&实现 LDAP基本模型目录树&名词解释分布式 LDAP的操作 LDAP是什么&#xff1f; …