Java包装类、自动装箱与拆箱知识总结

2023-11-14

因为在学习集合时知道集合里存放的对象都是Object类型,取出的时候需要强制类型转换为目标类型(使用泛型集合不需要),如int a = (Integer)arrayList.get(0);然后我们就会发现,为什么要强制转换为Integer,而不是int呢?int与Integer有什么区别呢?

1、基本类型与包装类区别

int是基本类型,直接存数值;如:

int i = 5;//直接在栈中分配空间,存放5这个数值

Integer是int的包装类,是类,拥有方法;如:

Integer i = new Integer(5);	//i是对象的引用变量,所以在堆内存中分配对象空间,栈中存放堆内存中对应空间的地址

Java有八种基本数据类型,对应八种包装类:

short Short

int Integer

long Long

char Character

byte Byte

float Float

boolean Boolean

double Double

变量的值存储在栈里,而对象存储在堆里,相比而言,堆栈更高效,这也是java保留基本类型的原因。包装类创建的对象,可以使用api提供的一些有用的方法。更为强大。

2、自动装箱与自动拆箱

那我们来分析Integer i = 5;的过程;

在jdk1.5以前,这样的代码是错误的,必须要通过Integer i = new Integer(5);这样的语句实现;而在jdk1.5以后,Java提供了自动装箱的功能,只需Integer i = 5;这样的语句就能实现基本数据类型传给其包装类,JVM为我们执行了Integer i = Integer.valueOf(5);这就是Java的自动装箱。

相对应的,把基本数据从对应包装类中取出的过程就是拆箱;如

Integer i = 5;

int j = i;//这样的过程就是自动拆箱

源码方面,用一句话总结装箱和拆箱的实现过程:

装箱过程是通过调用包装器的valueOf方法实现的,而拆箱过程是通过调用包装器的 xxxValue方法实现的。(xxx代表对应的基本数据类型)

Integer i = new Integer(xxx)和Integer i =xxx;这两种方式的区别:
1)第一种方式不会触发自动装箱的过程;而第二种方式会触发;
2)在执行效率和资源占用上的区别。第二种方式的执行效率和资源占用在一般性情况下要优于第一种情况(注意这并不是绝对的)。

3、源码问题、面试问题:(参考http://www.cnblogs.com/dolphin0520/p/3780005.html)

a、这里就有一个面试经常会出现的问题,看下面这段代码:

public class Main {
    public static void main(String[] args) {
         
        Boolean i1 = false;
        Boolean i2 = false;
        Boolean i3 = true;
        Boolean i4 = true;
         
        System.out.println(i1==i2);
        System.out.println(i3==i4);
    }
}
输出结果是什么呢?

true

false

出现这样结果的原因可由源码解释:

public static Integer valueOf(int i) {
    if(i >= -128 && i <= IntegerCache.high)  // 没有设置的话,IngegerCache.high 默认是127
        return IntegerCache.cache[i + 128];
    else
        return new Integer(i);
}

而其中IntegerCache类的实现为:

private static class IntegerCache {
        static final int high;
        static final Integer cache[];

        static {
            final int low = -128;

            // high value may be configured by property
            int h = 127;
            if (integerCacheHighPropValue != null) {
                // Use Long.decode here to avoid invoking methods that
                // require Integer's autoboxing cache to be initialized
                int i = Long.decode(integerCacheHighPropValue).intValue();
                i = Math.max(i, 127);
                // Maximum array size is Integer.MAX_VALUE
                h = Math.min(i, Integer.MAX_VALUE - -low);
            }
            high = h;

            cache = new Integer[(high - low) + 1];
            int j = low;
            for(int k = 0; k < cache.length; k++)
                cache[k] = new Integer(j++);
        }

        private IntegerCache() {}
    }
从这2段代码可以看出,在通过valueOf方法创建Integer对象的时候,如果数值在[-128,127]之间,便返回指向IntegerCache.cache中已经存在的对象的引用;否则创建一个新的Integer对象。
  上面的代码中i1和i2的数值为100,因此会直接从cache中取已经存在的对象,所以i1和i2指向的是同一个对象,而i3和i4则是分别指向不同的对象。


b、而如果把上一道题中的四个数据类型换做Double或Float,那么结果是什么?

public static void main(String[] args) {
         
        Double i1 = 100.0;
        Double i2 = 100.0;
        Double i3 = 200.0;
        Double i4 = 200.0;
         
        System.out.println(i1==i2);
        System.out.println(i3==i4);
    }
}
答案是都为false! 至于具体为什么,读者可以去查看Double类的valueOf的实现。

  在这里只解释一下为什么Double类的valueOf方法会采用与Integer类的valueOf方法不同的实现。很简单:在某个范围内的整型数值的个数是有限的,而浮点数却不是。
注意,Integer、Short、Byte、Character、Long这几个类的valueOf方法的实现是类似的。Double、Float的valueOf方法的实现是类似的。


c、换做Boolean呢?

public class Main {
    public static void main(String[] args) {
         
        Boolean i1 = false;
        Boolean i2 = false;
        Boolean i3 = true;
        Boolean i4 = true;
         
        System.out.println(i1==i2);
        System.out.println(i3==i4);
    }
}
答案是都为true!

至于为什么是这个结果,看了Boolean类的源码也会一目了然。下面是Boolean的valueOf方法的具体实现:

public static Boolean valueOf(boolean b) {
        return (b ? TRUE : FALSE);
    }

而其中的 TRUE 和FALSE又是什么呢?在Boolean中定义了2个静态成员属性:

 public static final Boolean TRUE = new Boolean(true);

    /** 
     * The <code>Boolean</code> object corresponding to the primitive 
     * value <code>false</code>. 
     */
    public static final Boolean FALSE = new Boolean(false);

至此,大家应该明白了为何上面输出的结果都是true了。

d、下面这段代码输出什么?

public class Main {
    public static void main(String[] args) {
         
        Integer a = 1;
        Integer b = 2;
        Integer c = 3;
        Integer d = 3;
        Integer e = 321;
        Integer f = 321;
        Long g = 3L;
        Long h = 2L;
         
        System.out.println(c==d);
        System.out.println(e==f);
        System.out.println(c==(a+b));
        System.out.println(c.equals(a+b));
        System.out.println(g==(a+b));
        System.out.println(g.equals(a+b));
        System.out.println(g.equals(a+h));
    }
}
先别看输出结果,读者自己想一下这段代码的输出结果是什么。这里面需要注意的是: 当 "=="运算符的两个操作数都是 包装器类型的引用,则是比较指向的是否是同一个对象,而如果其中有一个操作数是表达式(即包含算术运算)则比较的是数值(即会触发自动拆箱的过程)。 另外,对于包装器类型,equals方法并不会进行类型转换。明白了这2点之后,上面的输出结果便一目了然:

true
false
true
true
true
false
true
 第一个和第二个输出结果没有什么疑问。第三句由于  a+b包含了算术运算,因此会触发自动拆箱过程(会调用intValue方法),因此它们比较的是数值是否相等。而对于c.equals(a+b)会先触发自动拆箱过程,再触发自动装箱过程,也就是说a+b,会先各自调用intValue方法,得到了加法运算后的数值之后,便调用Integer.valueOf方法,再进行equals比较。同理对于后面的也是这样,不过要注意倒数第二个和最后一个输出的结果(如果数值是int类型的,装箱过程调用的是Integer.valueOf;如果是long类型的,装箱调用的Long.valueOf方法)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java包装类、自动装箱与拆箱知识总结 的相关文章

  • 唯一索引或主键违规:“PRIMARY KEY ON PUBLIC.xxx”; SQL语句

    每当我的应用程序启动时 我都会收到以下错误消息 Caused by org h2 jdbc JdbcSQLException Unique index or primary key violation PRIMARY KEY ON PUBL
  • 在 JTable 中移动行

    我使用 MVC 模式 并且有一个如下所示的 JTable List
  • JavaMail Gmail 问题。 “准备启动 TLS”然后失败

    mailServerProperties System getProperties mailServerProperties put mail smtp port 587 mailServerProperties put mail smtp
  • 如何在 JFace 的 TableViewer 中创建复选框?

    我创建了一个包含两列的 tableViewer 我想将其中一列设为复选框 为此 我创建了一个 CheckBoxCellEditor 但我不知道为什么它不起作用 名为 tableName 的列显示其值正常 色谱柱规格如下 String COL
  • 如何在一行中将字符串数组转换为双精度数组

    我有一个字符串数组 String guaranteedOutput Arrays copyOf values values length String class 所有字符串值都是数字 数据应转换为Double QuestionJava 中
  • AES 加密 Java/plsql

    我需要在Java和plsql DBMS CRYPTO for Oracle 10g 上实现相同的加密 解密应用程序 两种实现都工作正常 但这里的问题是我对相同纯文本的加密得到了不同的输出 下面是用于加密 解密过程的代码 Java 和 PLS
  • 在Windows上安装Java 11 OpenJDK(系统路径问题)

    Java 11 最近发布了 众所周知 这个版本没有安装文件 当然 要在没有安装程序的情况下安装 Java 我将系统设置 PATH 和 JAVA HOME 设置为解压缩 Java 11 的文件夹的地址 根据对类似问题的已接受回复建议 唯一的事
  • JNI 不满意链接错误

    我想创建一个简单的 JNI 层 我使用Visual studio 2008创建了一个dll Win 32控制台应用程序项目类型 带有DLL作为选项 当我调用本机方法时 出现此异常 Exception occurred during even
  • 在浏览器中点击应用程序时播放框架挂起

    我正在 Play 中运行一个应用程序activator run 也许 5 次中有 3 次 它会挂起 当我去http localhost 9000 它就永远坐在那里旋转 我看到很多promise timed out错误也 我应该去哪里寻找这个
  • java中删除字符串中的特殊字符?

    如何删除字符串中除 之外的特殊字符 现在我用 replaceAll w s 它删除了所有特殊字符 但我想保留 谁能告诉我我该怎么办 Use replaceAll w s 我所做的是将下划线和连字符添加到正则表达式中 我添加了一个 连字符之前
  • HDFS:使用 Java / Scala API 移动多个文件

    我需要使用 Java Scala 程序移动 HDFS 中对应于给定正则表达式的多个文件 例如 我必须移动所有名称为 xml从文件夹a到文件夹b 使用 shell 命令我可以使用以下命令 bin hdfs dfs mv a xml b 我可以
  • jdbc4.MySQLSyntaxErrorException:数据库中不存在表

    我正在使用 SpringBoot 开发一个网络应用程序 这是我的application properties文件来指定访问数据库的凭据 spring datasource driverClassName com mysql jdbc Dri
  • 使用替换字符串中多个单词的最有效方法[重复]

    这个问题在这里已经有答案了 此刻我正在做 Example line replaceAll replaceAll cat dog replaceAll football rugby 我觉得那很丑 不确定有更好的方法吗 也许循环遍历哈希图 ED
  • OnClick 事件中的 finish() 如何工作?

    我有一个Activity一键退出Activity 通过layout xml我必须设置OnClick事件至cmd exit调用 this finish 效果很好 public void cmd exit View editLayout thi
  • Microsoft Graph 身份验证 - 委派权限

    我可以使用 Microsoft Graph 访问资源无需用户即可访问 https developer microsoft com en us graph docs concepts auth v2 service 但是 此方法不允许我访问需
  • 请求位置更新参数

    这就是 requestLocationUpdates 的样子 我使用它的方式 requestLocationUpdates String provider long minTime float minDistance LocationLis
  • 应用程序关闭时的倒计时问题

    我制作了一个 CountDownTimer 代码 我希望 CountDownTimer 在完成时重新启动 即使应用程序已关闭 但它仅在应用程序正在运行或重新启动应用程序时重新启动 因此 如果我在倒计时为 00 10 分钟 秒 时关闭应用程序
  • 运行 Jar 文件时出现问题

    我已将 java 项目编译成 Jar 文件 但运行它时遇到问题 当我跑步时 java jar myJar jar 我收到以下错误 Could not find the main class myClass 类文件不在 jar 的根目录中 因
  • 查看Jasper报告执行的SQL

    运行 Jasper 报表 其中 SQL 嵌入到报表文件 jrxml 中 时 是否可以看到执行的 SQL 理想情况下 我还想查看替换每个 P 占位符的值 Cheers Don JasperReports 使用 Jakarta Commons
  • android Accessibility-service 突然停止触发事件

    我有一个 AccessibilityService 工作正常 但由于开发过程中的某些原因它停止工作 我似乎找不到这个原因 请看一下我的代码并告诉我为什么它不起作用 public class MyServicee extends Access

随机推荐

  • Docker之Alpine制作镜像且上传至阿里云

    Alpine制作jdk镜像 alpine Linux简介 Alpine Linux是一个轻型Linux发行版 它不同于通常的Linux发行版 Alpine采用了musl libc 和 BusyBox以减少系统的体积和运行时的资源消耗 alp
  • 8位深, 16位深,24位深,32位深图片显示原理及对比

    我们都知道一张图片可以保存为很多种不同的格式 比如bmp png jpeg gif等等 这个是从文件格式的角度看 我们抛开文件格式 看图片本身 我们可以分为8位 16位 24位 32位等 单击右键 属性 gt 详细信息即可查看图片位深度 8
  • ijkplayer-android编译 兼容多视频格式

    用的播放器框架是ijkplayer 然后就去https github com Bilibili ijkplayer的issue里找答案发现很多人遇到了这个问题 最终还是想通过编译定制化so的方式解决 践行解决方案 按照官方文档编译andro
  • Mybatis-代码走查问题整理

    实践篇 1 和 的区别 直接替换变量 有sql注入风险 使用场景 当表名 字段名作为变量传入时 PreparedStatement 预处理编译 先替换为 然后赋值 添加单引号 2 使用注解和xml文件sql的方式区别 注解 简单明了 无需额
  • Doris之Binlog Load

    Binlog Load Binlog Load提供了一种使Doris增量同步用户在Mysql数据库的对数据更新操作的CDC Change Data Capture 功能 适用场景 INSERT UPDATE DELETE支持 过滤Query
  • Qt6教程之三(3) QtWedget自定义控件

    在之前的博客中 我们使用的控件都是Qt官方提供的 对于控件的特性也只能被动地接受 为了打破这种束缚 可以按照自己的想法来定义控件 不过自定义控件必须遵守Qt官方的一套自定义控件规则 在规则之下我们就可以定义属于我们自己的控件啦 QWidge
  • 输出比较实验

    转载链接 输出比较 输出比较就是通过定时器的外部引脚对外输出控制信号 输出比较的模式有哪些 可以设置为以下几种不同的模式 翻译如下 000 冻结 输出比较寄存器TIMx CCR1中的内容与计数器TIMx CNT中的内容之间的比较对输出无影响
  • jquery ajax 无效字符,【JQuery】 ajax 无效的JSON基元

    如题 个人理解就是 你向传数据 josn格式 了 但是后台接受确不是json格式的 数据 贴段代码 var strJson usercode 123 password 123 ajax type POST url Index doLogin
  • CentOS7下安装 mysql5.7.25(glibc版)(可用)

    一 安装前的检查 1 检查 linux 系统版本 root localhost cat etc system release 2 检查是否安装了 mysql mysql 有三种安装方式 二进制包安装 RPM包安装 源码装 3 系统内存检查
  • c++的cout输出

    1 c 的cout输出顺序是从左往右进行输出 但是是从右往左压入栈 2 c 的cout的输出是遇到函数是若函数内右cout的操作则立即执行 3 不同编译器对相同语句的编译规则是不一样的 所以最好不要对同一变量进行多次的修改 也不用深究 没有
  • go语言如何编译为可执行文件

    使用系统自带的cmd找到main函数所在位置 1 go build go即可把go程序编译成exe文件 2 go run go就可以运行go程序了 3 便宜源代码 官方说使用go build fileName 编译出来的就直接带有调试信息了
  • bash: ifconfig: 未找到命令 解决方案

    解决思路 1 ifconfig 命令存在的情况 首先查看 ifconfig 命令在哪个目录下 顺便检查是否安装了这个命令 whereis ifconfig 然后查看 echo PATH PATH 中是否包含了这个目录 一般情况下是不包含的
  • 前端开发都需要掌握那些技术?

    前端技术多且杂 那么作为前端开发者 我们可以从那些方面进行进阶提升呢 本文从以下几个方面进行了整理归纳 内容如下 一 网页开发 二 小程序 三 移动端 四 桌面端 五 其他技术 一 网页开发 这里指PC端网页开发 要求的技术主要有以下几类
  • 华为OD机试(JAVA)真题 -- 最长(连续)子串

    import java util Scanner 给定一个字符串 只包含字母和数字 按要求找出字符串中的最长 连续 子串 字符串本身是其最长的子串 子串要求 只包含 1 个字母 a z A Z 其余必须是数字 字母可以在子串中的任意位置 如
  • shell自动部署docker及docker-compose

    一 准备环境 centos7 6及centos7 9已通过测试 测试时服务器刚刚完成初始化 未修改任何配置 可以直接运行脚本进行安装 要求主机可以访问互联网 yum环境在脚本中已自动准备 将两个脚本直接复制放到root目录下 赋予可执行权限
  • NGUI学习笔记汇总

    NGUI学习笔记汇总 适用于NGUI2 x NGUI3 x 一 NGUI的直接用法 1 Attach a Collider 表示为NGUI的某些物体添加碰撞器 如果界面是用NGUI做的 只能这样添加 注 用Component添加无效 2 A
  • 前端WEB安全

    一 浏览器安全 首先了解前端web安全知识 比不可绕开的基础就是同源策略了 同源策略 Same Origin Policy 是一种约定 它是浏览器最核心也最基本的安全功能 如果缺少了同源策略 则浏览器的正常功能可能都会受到影响 可以说Web
  • 你想改变现在的生活吗?

    你想改变现在的生活吗 你想加薪吗 想买车吗 想找到你生命中的另一半吗 去学习吧 学校是个神奇的地方
  • 记一次解决联想笔记本冬天卡顿反应慢的方法

    个人简介 个人主页 九黎aj 幸福源自奋斗 平凡造就不凡 如果文章对你有用 麻烦关注点赞收藏走一波 感谢支持 欢迎订阅我的专栏 autojs 图携带方便买了一个联想笔记本 然后发现笔记本充电时候正常 不卡 不充电时候会卡0 4Ghz ctr
  • Java包装类、自动装箱与拆箱知识总结

    因为在学习集合时知道集合里存放的对象都是Object类型 取出的时候需要强制类型转换为目标类型 使用泛型集合不需要 如int a Integer arrayList get 0 然后我们就会发现 为什么要强制转换为Integer 而不是in