53从零开始学Java之Integer底层原理探究

news2024/11/24 11:31:23

作者:孙玉昌,昵称【一一哥】,另外【壹壹哥】也是我哦

千锋教育高级教研员、CSDN博客专家、万粉博主、阿里云专家博主、掘金优质作者

前言

在之前的两篇文章中,壹哥给大家介绍了Java中的包装类及其特点、用法,但是这些内容主要是停留在”怎么用“的层面,没有太多涉及”为什么“,所以接下来壹哥会给大家讲一讲Integer这个包装类的底层原理。在现在的就业环境下,我们需要知其然,还要知其所以然,才能更好地满足就业需求。

------------------------------------------------前戏已做完,精彩即开始----------------------------------------------

全文大约【3200】字,不说废话,只讲可以让你学到技术、明白原理的纯干货!本文带有丰富的案例及配图视频,让你更好地理解和运用文中的技术概念,并可以给你带来具有足够启迪的思考......

配套开源项目资料

Github:

https://github.com/SunLtd/LearnJava

Gitee:

一一哥/从零开始学Java

一. Integer底层原理探究

1. int和Integer的区别

在前面的内容介绍中,壹哥给大家讲过Integer这个类,现在大家对它的用法应该都比较清楚了。但是除了要掌握Integer的用法之外,我们还要了解它的一些底层内容,因为在面试时,关于Integer的底层考察的比较多。比如一个常见的面试题是这样的:请问int和Integer的区别有哪些?

面对这样的一道题目,你该怎么回答?常规的答案其实很容易答出来,比如:

  • int是基本数据类型,代表整型数据,默认值是0;
  • Integer是 int的包装类,属于引用类型,默认值为null
  • int 和 Integer 都可以表示某一个整型数值;
  • Integer变量实际是对象的引用,当new一个Integer时,实际上是生成一个指针指向此对象;而int则是直接存储数据值;
  • Integer可以区分出未赋值和值为 0 的区别,而int 则无法表达出未赋值的情况;
  • int 和 Integer 不能够互用,因为他们是两种不同的数据类型;
  • int在初始化时,可以直接写成 int=1 的形式;
  • 因为Integer是包装类型,使用时可以采用 Integer i = new Integer(1) 的形式,但因为Java中的自动装箱和拆箱机制,使得对Integer类的赋值也可以使用 Integer i= 1 的形式;
  • 如果我们只是进行一些加减乘除的运算 或者 作为参数进行传递,那么就可以直接使用int这样的基本数据类型;但如果想按照对象来进行操作处理,那么就要使用Integer来声明一个对象。

但是如果你只能回答出这样的答案,你在面试官的眼里只能算合格,还算不上优秀,我们需要对Integer了解地更多一些。

2. 被final修饰的Integer类

为了搞清楚Integer的底层,我们就不得不研究一下它的源码,我们来追踪一下Integer源码,如下图所示:

从源码中可以看出,Integer是Number的一个子类,且被final所修饰!请大家回顾一些壹哥之前讲过的final知识点。我们知道,被final修饰的类是常量类,该类不能被继承,里面的方法不能被重写,创建出的对象也不能被修改!总之,Integer符合final类的特征。

3. IntegerCache缓冲区

我们还记得,在Integer中有一个valueOf()方法,该方法可以将int值转为Integer对象。接下来我们来看看该方法的实现源码,如下图所示:

从上图的源码截图中我们可以看到,Integer中有一个缓冲区叫做IntegerCache,这是Integer中的一个内部类,如下图所示:

我们可以看到,low就是-128,high等于127,这是缓冲区的最低和最高边界。那么这个缓冲区的存在到底有什么用呢?大家别着急,我们先做几个核心实验。

4. 几个核心实验

为了能够讲清楚Integer的底层逻辑,壹哥给大家设计了如下代码,用于验证Integer的底层设计。

4.1 比较new出的两个Integer对象

我们通过new对象的方式,来创建两个Integer对象i和j,并比较这两个对象。

//通过new生成的两个Integer变量进行比较,结果为false
Integer i = new Integer(100);
Integer j = new Integer(100);
System.out.print(i == j); //false

从运行的结果中可以看出,通过new生成的两个Integer对象永远是不会相等的。这是因为new生成的是两个对象,Integer变量实际上是对Integer对象的引用,这两个对象的内存地址是不同的。

4.2 Integer对象和int变量进行比较

接下来我们在把一个Integer对象和int变量进行比较,如下:

Integer i = new Integer(100);

int j = 100;

System.out.print(i == j); //true

Integer变量和int变量进行比较时,只要两个变量的值是相等的,结果就为true。这是因为Integer包装类和int基本类型进行比较时,Java会进行自动拆箱操作,将Integer转为了int,然后再进行比较,实际上就变为了两个int变量的比较。本案例中两者的值都是100,所以用“==”等号进行比较时自然就是相等的。

4.3 非new的Integer变量和new出的Integer变量进行比较

然后我们再把一个非new的Integer变量和new出的Integer变量进行比较,如下所示:

//非new生成的Integer变量和new Integer()生成的变量进行比较
Integer i = new Integer(100);
//自动装箱
Integer j = 100;
System.out.print(i == j); //false

在这段代码中,非new生成的Integer变量和new Integer()生成的变量进行比较时,结果却为false这是因为非new生成Integer变量时,内部会调用valueOf()方法,进行自动装箱操作,此时会把Integer变量的值指向Java常量池中的数据。而new Integer()生成的变量,则指向的是堆中新建的对象,两者在内存中的地址是不同的。

4.4 两个非new生成的Integer对象进行比较

接着我们再对两个非new生成的Integer对象进行比较,如下所示:

//两个非new生成的Integer对象进行比较
//i与j的取值范围是在 -128~127 之间!
Integer i = 100;
Integer j = 100;
System.out.print(i == j); //true

//x与y的取值范围不在 -128~127 之间!
Integer x = 200;
Integer y = 200;
System.out.print(x == y); //false

这段代码中,两个非new生成的Integer对象进行比较时,如果两个变量的取值在 -128到127 之间,则比较结果为true;如果两个变量的值不在此区间,则比较结果为false。这又是为什么呢? 其实要想弄明白这个原因,我们只需要看看Integer类的valueOf()方法是怎么写的就可以了。valueOf()方法源码如下:

//两个非new生成的Integer对象进行比较
//i与j的取值范围是在 -128~127 之间!
Integer i = 100;
Integer j = 100;
System.out.print(i == j); //true

//x与y的取值范围不在 -128~127 之间!
Integer x = 200;
Integer y = 200;
System.out.print(x == y); //false

我们知道,valueOf(int i)方法可以将int值自动装箱变成对应的Integer实例。并且从这段源码中我们可以看到其内部有一个if判断,根据判断结果的不同,会有2种不同的方式得到Integer对象:当arg大于等于-128且小于等于127时,则直接从缓存中返回一个已经存在的对象;如果参数的值不在这个范围内,则new一个Integer对象返回,要么new Integer,要么从int常量池中获取

之前我们构建Integer对象的传统方式是直接 new 一个Integer对象,内部会调用构造器。但是根据实践,我们发现大部分的数据操作都是集中在有限的、较小的数值范围内。因而在JDK 1.5中,新增了一个静态工厂方法valueOf(int i)。当我们进行Integer i=xxx 赋值操作时,Java内部会调用执行这个valueOf()实现自动装箱。而在调用valueOf()方法时,其内部会利用缓存机制,对取值在-128~127之间的int值进行缓存操作,这是在JDK 1.5 之后进行的一个可以明显改善性能的提升而按照Javadoc文档,该缓存机制默认会缓存在 -128 到 127 之间的值,不在该区间的值并不会进行缓存。所以,给Integer i赋值的大小不同,比较的结果也可能会不同。

4.5 ==和equals的区别

最后我们再做一个实验,来看看==与equals比较两个Integer对象时有什么不同。

Integer x = 127;
Integer y = 127;

Integer m = 100000;
Integer n = 100000;

System.out.println("x == y: " + (x==y)); // true
System.out.println("m == n: " + (m==n)); // false

System.out.println("x.equals(y): " + x.equals(y)); // true
System.out.println("m.equals(n): " + m.equals(n)); // true

从该实验中可以看出,==比较时,较小的两个相同的Integer会返回true,较大的两个相同的Integer会返回false。结合上面壹哥给大家的讲解,你思考一下这是为什么?

5. 结论

通过以上的几个核心实验,壹哥可以给大家梳理出一个结论:

当我们利用”==“等号比较两个Integer i 和 Integer j的值时,如果取值范围是在-128~127之间,两个相同的Integer值会返回true;如果不在该区间,两个相同的Integer值会返回false。这是因为Integer是final类,编译器把Integer i = 100; 自动变为Integer i = Integer.valueOf(100);。为了节省内存,Integer.valueOf()对于较小的数,始终会返回相同的实例对象,因此,==比较的结果就是true。

那么如果我们只是为了比较两个Integer对象的值是否相等,而不是为了比较两个对象的地址是否相同,在开发时请尽量使用equals()方法,而不是==!

并且我们现在还知道,在Java中有3种方式可以构造出一个Integer对象,代码如下:

//方法1:
Integer i = new Integer(100);

//方法2:
Integer i = Integer.valueOf(100);

//方法3:
Integer i = 100;

实际上,方法2和方法3的本质是一样的,所以开发时为了简洁,我们一般是通过方法3来得到一个Integer对象。但是尽量不要使用方法1来构建Integer对象,这是因为方法1总是会创建一个新的Integer实例,而方法2和方法3则会尽可能地返回缓存的实例对象,以节省内存。

所以最终关于”int和Integer的区别有哪些“这道面试题的答案,如果你想拿到高分,就需要把Integer的底层原理也回答出来才行!如果你可以把以上内容都回答清楚,我相信单凭这一道题目,就足以让面试官对你刮目相看!

壹哥在自己的面试题精讲专栏中,对此题目有着非常细致地讲解,这里不再赘述,大家可以参考如下链接:

高薪程序员&面试题精讲系列04之说说int与Integer的区别及底层原理

------------------------------------------------正片已结束,来根事后烟----------------------------------------------

二. 结语

这样 壹哥 就给大家分析了 “int和Integer的区别有哪些” 这个面试题,猛一看很简单,实际涉及的内容很多!最后我再梳理一下该问题的回答要点:

  1. 先简单回顾Java中的数据类型及取值范围;
  2. 然后简介基本类型与包装类,最后还能说明为什么需要有包装类;
  3. 接着说一下int与Integer的基本区别;
  4. 最后再说int与Integer的深入区别,即底层的源码和原理。

如果你可以把我总结的这4点都能回答好,就这一个问题,面试官就会对你留下深刻的影响,他就会认为你的基础知识足够扎实,因为大多数人只会回答int和Integer的基本区别,很少有人去回答底层的内容!而通过这个问题,面试官也会了解到,你对Java的内存分配是很熟悉的!

另外如果你独自学习觉得有很多困难,可以加入壹哥的学习互助群,大家一起交流学习。

三. 今日作业

请回答”int和Integer有哪些区别?“,评论区给出你的答案。

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

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

相关文章

正则表达式——Java

1、简介 正则表达式(Regular Expression)又称正规表示法、常规表示法,在代码中常简写为 regex、regexp 或 RE,它是计算机科学的一个概念。 String 类里也提供了如下几个特殊的方法。 boolean matches(String regex)&#xff1a…

小研究 - 面向 Java 的高对抗内存型 Webshell 检测技术(四)

由于 Web 应用程序的复杂性和重要性, 导致其成为网络攻击的主要目标之一。攻击者在入侵一个网站后, 通常会植入一个 Webshell, 来持久化控制网站。但随着攻防双方的博弈, 各种检测技术、终端安全产品被广泛应用, 使得传统的以文件形式驻留的 Webshell 越来越容易被检测到, 内存…

视频做成GIF动图怎么做?分享超简单的制作方法

将视频制作GIF动图的好处在于它可以将原本较长的视频压缩成一个简短、易于分享的图像文件。这使得它们非常适合用于社交媒体、博客、电子邮件等场景,可以当做表情包来使用,尤其是看到一段搞笑的视频,想要把它做成GIF动图该怎么做呢&#xff1…

【System Verilog and UVM基础入门17】Using get_next_item()

从小父亲就教育我,做一个对社会有用的人! 关于握手协议的文章,网上有很多很多,这篇文章是最原滋原味的介绍,希望可以帮助到有缘人! uvm_driver #(REQ,RSP) The base class for drivers that initiate req…

CS 144 Lab One -- 流重组器

CS 144 Lab One -- 流重组器 实验结构如何调试StreamReassembler 实现 对应课程视频: 【计算机网络】 斯坦福大学CS144课程 Lab 1 对应的PDF: Lab Checkpoint 1: stitching substrings into a byte stream 实验结构 这幅图完整的说明了CS144 这门实验的结构: 其中…

MySQL约束和数据类型

目录 约束条件 MySQL数据类型 1、数值类型 2、字符串类型 3、日期时间类型 源码等资料获取方法 约束条件 约束条件就是在给字段加一些约束,使该字段存储的值更加符合我们的预期。 常用约束条件如下: UNSIGNED :无符号,值…

【数据结构与算法】哈夫曼编码(最优二叉树)实现

哈夫曼编码 等长编码:占的位置一样 变长编码(不等长编码):经常使用的编码比较短,不常用的比较短 最优:总长度最短 最优的要求:占用空间尽可能短,不占用多余空间,且不…

【MySQL】DML数据操纵语言(非常适合MySQL初学者学习)

🧑‍💻作者名称:DaenCode 🎤作者简介:啥技术都喜欢捣鼓捣鼓,喜欢分享技术、经验、生活。 😎人生感悟:尝尽人生百味,方知世间冷暖。 📖所属专栏:重…

清华大学携手蚂蚁集团,攻坚可信AI、安全通用大模型等关键技术

2023年4月7日,清华大学与蚂蚁集团签署合作协议,双方将在“下一代互联网应用安全技术”方向展开合作,聚焦智能风控、反欺诈等核心安全场景,携手攻坚可信AI、安全大模型等关键技术,并加速技术落地应用,以解决…

NodeJS内置模块 npm包管理工具 nvm版本管理工具 nrm镜像管理工具

Nodejs 下载 下载地址 node 是什么 node.js 是一个开源的,跨平台的 JavaScript 运行环境 运行 js 文件 node 文件.jsnodemon 监听文件变化 npm i nodemon -gnodemon 文件名全局变量 global globalThis node 中顶级对象为 global ,也可以使用 glo…

postgreSQL数据库的安装

文章目录 一、Linux 下安装 postgreSQL 数据库1.1、准备环境1.2、关闭防火墙跟SELinux1.2.1、关闭防火墙 firewalld1.2.2、关闭SELinux 1.3、挂载本地镜像1.4、软件包的下载postgreSQL 一、Linux 下安装 postgreSQL 数据库 1.1、准备环境 操作系统IP应用Red Hat 8192.168.192…

类加载的过程(简单介绍)

目录 一、类加载过程一览 加载: 验证: 准备: 解析: 初始化: 二:类加载器分类 启动类加载器(bootstrap class loader) 扩展类加载器(extensions class loader&…

Nginx外网访问内网如何实现

1、背景 项目要求:将甲方内网的项目能够对外访问,甲方提供一个中间过渡服务器,中间过渡服务器与外网互通,且中间服务器可以访问内网; 外网客户端->中间过渡服务器开放端口:80 中间过渡服务器->内网服…

Cadence Allegro PCB设计88问解析(三十一) 之 Allegro 中 打印(Plot)设置

一个学习信号完整性仿真的layout工程师 在PCB进行投板时,往往会打印一下装备层(Assembly),给贴片,用于核对器件的信息等。下面简单介绍Allegro中打印(Plot)设置。 1. 在Allegro的菜单下选择File命令,点击Plot Setup,会…

无线振弦采集仪应用于岩土工程安全监测的解决方案

无线振弦采集仪应用于岩土工程安全监测的解决方案 随着现代岩土工程的发展,工程规模越来越大,地质灾害频发,安全监测成为岩土工程的重要组成部分。传统的安全监测方法存在一些局限性,如无法实时监测,监测精度不高等问…

途乐证券-沪指震荡跌0.25%,半导体等板块走弱,地产等板块拉升

19日早盘,沪指窄幅震动下探,深成指、创业板指均走低;两市半日成交约4300亿元,北向资金净卖出超40亿元。 截至午间收盘,沪指跌0.25%报3189.81点,深成指跌0.51%,创业板指跌1%;两市合计…

《2023购物中心运营数字化白皮书》正式发布!|爱分析报告

在国家政策鼓励线下实体经济发展、鼓励消费的大背景下,购物中心的发展潜力巨大。但另一方面,随着行业进入存量时代,竞争愈发激烈,品牌扩张乏力,购物中心招商压力增大。以数字化手段加持的精细化运营,成为购…

侦听器watch

在代码逻辑中监听某个数据的变化&#xff0c;这个时候就需要用侦听器 watch 来完成了&#xff1b; 1.data的watch <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge&q…

备战秋招 | 笔试强训6

目录 一、选择题 二、编程题 三、选择题题解 四、编程题题解 一、选择题 1、十进制变量i的值为100&#xff0c;那么八进制的变量i的值为&#xff08;&#xff09; A. 146 B. 148 C. 144 D. 142 2、执行下面语句后的输出为 int I1; if(I<0)printf("****\n") …

Java框架 Mybatis入门

0目录 Java框架Mybatis 1..框架介绍 2.Mybatis实战 1.框架介绍 补充MVC思想 为什么使用框架&#xff1f; 效率高&#xff0c;成本低 框架是别人写好的&#xff0c;可以直接调用 框架是基于MVC的思想 框架包中含有MVC思想的所有组成模块&#xff1a;控制层&#xff1b;模型…