Java的自动拆/装箱
作者:Alvin
关键字:语法糖 类 对象
参考
前言
我们知道,Java有8中基本数据类型,分别是byte,short,int,long,char,float,double,boolean,但是定义的这些基本数据类型的值只是一个字面量,而字面量的补码是的的确确存储在内存上的一个量,这个量不具有其他的方法属性。但是我们在编程开发中有把一个整型int转换成字符串等的需求,再如当我们需要把数据放到集合中时,我们的基本数据类型是不允许被放入的,而Java中的中心思想就是对象,所以Java将它们封装成对象Byte、Short、Integer、Long、 Character、Float、Double、Boolean,并给出相应的方法。这样当我们有需求的时候我们就可以通过相对应的对象进行调用方法来解决。
一、案例引入
public static void main(String[] args) {
Integer i = 10;
Integer j = 10;
System.out.println(i == j); Integer a = 128;
Integer b = 128;
System.out.println(a == b); int k = 10;
System.out.println(k == i);
int kk = 128;
System.out.println(kk == a); Integer m = new Integer(10);
Integer n = new Integer(10);
System.out.println(m == n);
}
执行结果
true
false
true
true
false
二、写法分析
在进行分析之前我们先来了解一个概念:语法糖
语法糖(Syntactic sugar),也译为糖衣语法,是由英国计算机科学家彼得·约翰·兰达(Peter J. Landin)发明的一个术语,指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。通常来说使用语法糖能够增加程序的可读性,从而减少程序代码出错的机会。
Java中的语法糖也是新增了一些语法,使得程序员使用更加方便。但是计算机底层还是使用基本语法来实现的。下面我们讨论几个经常使用到的语法糖,可变参数、自动装箱/拆箱、增强for循环。
我们以Integer类为例,在我们用如下代码编写程序后,当使用Javac.exe工具操作之后,编译器会把我们的这个程序重写按照DRY(Don't repeat yourself)原则进行编译
public class Test { public static void main(String[] args) {
Integer num1 = 123;//将一个基本数据类型赋给Integer对象
int num2 = num1;//将一个Integer对象赋给整形变量
}
}
对以上代码编译后的Test.class反编译结果如下
public class Test{
public static void main(String[] args) {
Integer num1 = Integer.valueOf(123);//装箱操作
int num2 = num1.intValue();//拆箱操作
}
}
Java语言中,javac命令可以将后缀名为.java的源文件编译为后缀名为.class的可以运行于Java虚拟机的字节码。如果你去看com.sun.tools.javac.main.JavaCompiler的源码,你会发现在compile()中有一个步骤就是调用desugar(),这个方法就是负责解语法糖的实现的。
可以看到,在Java编译器进行编译的时候会自动把我们的代码重整成符合DRY原则代码并编译成.class文件。在我们定义一个Integer类型的变量后,当我们把整型的值赋值给该Integer类型,实际上在编译后的操作时执行了Integer.valueOf(123);操作,只是我们采用了语法糖写法而简写了方法调用的过程,同理,当把一个Integer的对象用语法糖写法编写的时候,该对象也调用了它的intValue方法进行转换类型。所以我们语法糖写法只是在编写的时候简化了代码,而类型的转换操作在编译器运行的时候会把调用的方法重新补充上。其他的八个基本数据类型各自对应的情况和Integer相同,不再赘述。
其他类似的语法糖写法还有增强for循环(底层还是循环),可变参数,switch对String和枚举的支持等
三、结果分析
了解了上面代码的转换过程,我们从反编译的结果得知:再Java语言中永远遵守不同类型之间不可以进行赋值的规则。置于我们在代码中的编写形式有时只是进行了简写,而最后的执行还要依赖于编译器的解析结果。
四、实现过程
上方就是基本数据类型的自动拆/装箱,他们的装箱遵循以下规则
自动装箱规范要求 byte<= 127、char<=127、-128<=short <=127、-128<=int <=127都被包装到固定的对象中(缓存)。
也就是说在装箱过程中执行valueOf(参数)方法后,如果满足以上条件就会被封装成Integer对象中。valueOf函数如下
从函数可以看出,当在-128到127范围内,会生成同一个对象,在范围之外,会执行new Integer();我们都知道在Java语言中,new
一个对象是存储在堆里的,我们通过栈中的引用来使用这些对象;所以,对象本身来说是比较消耗资源的。
五、总结
包装类的应用
1、Java中的集合类只能接收对象类型,而Java通过包装类实现了把基本数据类型放入集合操作的目的。并且在放入集合的时候这种封装时自动完成的。
2、包装类与基本数据类型进行比较运算,是先将包装类进行拆箱成基本数据类型,然后进行比较的。
3、两个包装类型之间的运算,会被自动拆箱成基本类型进行。
4、三目运算符flag ? i : j;
片段中,三目运算符的语法规范:当第二,第三位操作数分别为基本类型和对象时,其中的对象就会拆箱为基本类型进行操作。如果这个时候i的值为null
,那么久会发生NPE。(自动拆箱导致空指针异常)
5、函数参数与返回值
6、Integer中的缓存机制有关。在Java 5中,在Integer的操作上引入了一个新功能来节省内存和提高性能。整型对象通过使用相同的对象引用实现了缓存和重用。适用于整数值区间-128 至 +127。只适用于自动装箱。使用构造函数创建对象不适用。当需要进行自动装箱时,如果数字在-128至127之间时,会直接使用缓存中的对象,而不是重新创建一个对象。
另外javadoc详细的说明了缓存支持-128到127之间的自动装箱过程。最大值127可以通过-XX:AutoBoxCacheMax=size修改。实际上这个功能在Java 5中引入的时候,范围是固定的-128 至 +127。后来在Java 6中,可以通过java.lang.Integer.IntegerCache.high设置最大值。
六、注意事项
包装类的使用简化了代码,方便了编程者对数据的操作,实现了面向对象思想,但是也引入了一些麻烦,我们要尽量避免,以防对以后的编程中出现负担。
1、包装对象的数值比较,不能简单的使用==
,虽然-128到127之间的数字可以,但是这个范围之外还是需要使用equals
比较。
2、如果一个for循环中有大量拆装箱操作,会浪费很多资源。
3、有些场景会进行自动拆装箱,同时也说过,由于自动拆箱,如果包装类对象为null,那么自动拆箱时就有可能抛出NPE。
Java的自动拆/装箱的更多相关文章
- Java之自动拆装箱
顾名思义,自动拆装箱就是将基本类型和包装类进行自动的互相转换. JDK5.0后,将自动装箱/拆箱引Java中. 自动装箱的过程:每当需要一种类型的对象时,这种基本类型就自动地封装到与它相同类型的包装中 ...
- Java的自动拆装箱与Integer的缓存机制
转载请注明原文地址:https://www.cnblogs.com/ygj0930/p/10832303.html 一:基本类型与包装类型 我们知道,Java有8大基本数据类型,4整2浮1符1 ...
- 关于java的自动拆装箱若干细节问题
一.首先需要了解的几个前提: 1.自动装箱过程是通过调用valueOf方法实现的(如Integer.valueOf(10)),而拆箱过程是通过调用包装器的 xxxValue方法实现的(如Integer ...
- java中的自动拆装箱与缓存(Java核心技术阅读笔记)
最近在读<深入理解java核心技术>,对于里面比较重要的知识点做一个记录! 众所周知,Java是一个面向对象的语言,而java中的基本数据类型却不是面向对象的!为了解决这个问题,Java为 ...
- 《java入门第一季》之Integer类和自动拆装箱概述
/ * int 仅仅是一个基本类型.int有对应的类类型,那就是Integer. * 为了对基本数据类型进行更多的操作,更方便的操作,Java就针对每一种基本数据类型提供了对应的类类型--包装类类型 ...
- java的数据类型、自动拆装箱、字面量
java 中的数据类型分为两大类:值类型(基本数据类型)和引用类型(复合数据类型) 值类型分为 1,整数类型(byte,short,int,long) 2,浮点类型(float,double) 3, ...
- 一文读懂什么是Java中的自动拆装箱
基本数据类型 基本类型,或者叫做内置类型,是Java中不同于类(Class)的特殊类型.它们是我们编程中使用最频繁的类型. Java是一种强类型语言,第一次申明变量必须说明数据类型,第一次变量赋值称为 ...
- Java枚举、静态导入、自动拆装箱、增强for循环、可变参数
一.枚举简介 1.什么是枚举? 需要在一定范围内取值,这个值只能是这个范围内中的任意一个 现实场景:交通信号灯,有三种颜色,但是每次只能亮三种颜色里面的任意一个 2.使用一个关键字 enum enum ...
- 静态导入方法即自动拆装箱(java)
package example6;import static java.lang.System.out;import static java.util.Arrays.sort;import java. ...
随机推荐
- Linux ifconfig命令详解
ifconfig(interfaces config).通常需要以root身份登录或使用sudo来使用ifconfig工具 ifconfig 命令用来查看和配置网络设备.当网络环境发生改变时可通过此命 ...
- Hadoop HBase概念学习系列之HBase里的宽表设计概念(表设计)(二十七)
在下面这篇博文里,我给各位博客们,分享了创建HBase表,但这远不止打好基础. HBase编程 API入门系列之create(管理端而言)(8) 在关系型数据库里,表的高表和宽表是不存在的.在如HBa ...
- Centos7 Nginx 443端口反向代理springboot项目
开发微信小程序需要部署项目到服务器.要求必须是443端口.但是一个443端口只能监听一个服务器.所以就出现了一个问题就是每次开发一个小程序就需要买一个服务器.觉得特别多余.后来查到了有一种方式就是通过 ...
- .split("\n") 和 .strip("我是诗人的感叹")
s10='''诗人 学者 作家 # 这里面是有换行 "\n" 的, 要想变成一行, 删除strip不行,要用 split分开,这样就能变成一个列表,里面是各个字 ...
- 将一个文件中的内容,在另一个文件中生成. for line in f1, \n f2.write(line)
将一个文件中的内容,在另一个文件中生成. 核心语句: for line in f1: f1中的所有一行 f2.write(line) ...
- Alpha 冲刺报告(6/10)
Alpha 冲刺报告(6/10) 队名:洛基小队 峻雄(组长) 已完成:实现角色的移动. 明日计划:关于角色的属性设计. 剩余任务:角色的属性脚本 困难:角色的属性以及具体的编码 ---------- ...
- 「PKUWC2018」随机算法
题目 思博状压写不出是不是没救了呀 首先我们直接状压当前最大独立集的大小显然是不对的,因为我们的答案还和我们考虑的顺序有关 我们发现最大独立集的个数好像不是很多,可能是\(O(n)\)级别的,于是我们 ...
- 【转】iOS - SQLite 数据库存储
本文目录 1.SQLite 数据库 2.iOS 自带 SQLite 的使用 3.fmdb 的使用 4.fmdb 多线程操作 5.其他 SQLite 的第三方封装库 回到顶部 1.SQLite 数据库 ...
- sqoop工具介绍(hdfs与关系型数据库进行数据导入导出)
数据表 第一类:数据库中的数据导入到HDFS上 #数据库驱动jar包用mysql-connector-java--bin,否则有可能报错! ./sqoop import --connect jdbc: ...
- NYOJ17 最长单调递增子序列 线性dp
题目链接: http://acm.nyist.edu.cn/JudgeOnline/problem.php?pid=17 分析: i=1 dp[i]=1 i!=1 dp[i]=max(dp[j]+1) ...