Java的自动拆装箱

1、基本类型

Java基本类型共有八种,基本类型可以分为三类:

  • 字符类型char
  • 布尔类型boolean
  • 整数类型byte、short、int、long
  • 浮点数类型float、double。

  Java中的数值类型不存在无符号的,它们的取值范围是固定的,不会随着机器硬件环境或者操作系统的改变而改变。

基本类型的好处

  我们都知道在Java语言中,new一个对象是存储在堆里的,我们通过栈中的引用来使用这些对象;所以,对象本身来说是比较消耗资源的。

  对于经常用到的类型,如int等,如果我们每次使用这种变量的时候都需要new一个Java对象的话,就会比较笨重。

  所以,和C++一样,Java提供了基本数据类型,这种数据的变量不需要使用new创建,他们不会在堆上创建,而是直接在栈内存中存储,因此会更加高效。

2、包装类型

  Java语言是一个面向对象的语言,但是Java中的基本数据类型却是不面向对象的,这在实际使用时存在很多的不便,为了解决这个不足,在设计类时为每个基本数据类型设计了一个对应的类进行代表,这样八个和基本数据类型对应的类统称为包装类(Wrapper Class)。

下表是基本数据类型对应的包装器类型:

基本类型包装类型
int(4字节)Integer
byte(1字节)Byte
short(2字节)Short
long(8字节)Long
float(4字节)Float
double(8字节)Double
char(2字节)Character
boolean(未定)Boolean

3、自动装箱、拆箱

  JDK5开始就提供自动装、拆箱的语法糖。这里的装箱和拆箱的概念描述的其实就是Java中这八种基本数据类型和对应的包装类型之间的转换过程。我们把基本数据类型转换成对应的包装类型的过程叫做装箱。反之就是拆箱。在Java中的装箱和拆箱不是人为操作的,是程序在编译的时候编译器帮助我们完成这项任务的,因此说它是自动的。

JDK5之前,如果要生成一个数值为10的Integer对象,必须这样进行:

Integer i = new Integer(10);

从JDK5开始就提供了自动装箱的特性,如果要生成一个数值为10的Integer对象,只需要这样就可以了:

Integer i = 10;

4、自动装箱、拆箱如何实现的

以下面这段代码为例,查看其字节码

(
通过javac TestClass.java命令生成对应类的字节码文件
通过javap -verbose TestClass.class命令,反编译字节码文件
IDEA操作,可以通过右键复制类的路径,到对应类的所在目录下,输入命令行输入命令
)

public class Test {
	public static void main(String[] args) {
		Integer i=10;
		int x=i;
	}
}

在这里插入图片描述

  从反编译得到的字节码内容可以看出,在装箱的时候自动调用的是Integer的valueOf(int)方法。而在拆箱的时候自动调用的是Integer的intValue方法。其他的也类似。

5、自动装箱和拆箱的触发时机

自动装箱和拆箱的触发时机,具体如下:

  • 进行 = 赋值操作(装箱或拆箱)
  • 进行+,-,*,/混合运算 (拆箱)
  • 进行>,<,==比较运算(拆箱)
  • 调用equals进行比较(装箱)
  • ArrayList,HashMap等集合类 添加基础类型数据时(装箱)

6、自动拆装箱与缓存

首先,看下面一段代码,猜测其输出

public class Test {
	public static void main(String[] args) {
		Integer i1 = 100;
		Integer i2 = 100;
		Integer i3 = 200;
		Integer i4 = 200;

		System.out.println(i1==i2);
		System.out.println(i3==i4);
	}
}

看上面的代码,可能会认为连个都为false。虽然比较的值是相等的,但是由于比较的是对象,而对象的引用不一样,所以会认为两个i输出都是false的。

在Java中,==比较的是对象应用,而equals比较的是值。

结果:

在这里插入图片描述

原因就和Integer中的缓存机制有关。在Java 5中,在Integer的操作上引入了一个新功能来节省内存和提高性能。整型对象通过使用相同的对象引用实现了缓存和重用。

查看Integer的valueOf源码

在这里插入图片描述

在这里插入图片描述

  可以看出在valueOf方法创建Integer对象的时候,如果数值在[-128,127]之间,便返回指向IntegerCache.cache中已经存在的对象的引用;否则创建一个新的Integer对象。

注意,Integer、Short、Byte、Character、Long这几个类的valueOf方法的实现是类似的。
Double、Float的valueOf方法的实现是类似的。

看下面这段代码

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);
	}

在这里插入图片描述

对应的valueof方法
在这里插入图片描述

7、相关问题

1、

public class Test {
	public static void main(String[] args) {
		Integer num1 = 200;
		int num2 = 200;
		System.out.println(num1 == num2); //true
	}
}

在这里插入图片描述

说明num1 == num2进行了拆箱操作

2、

public static void main(String[] args) {
		Integer num1 = 100;
		int num2 = 100;
		System.out.println(num1.equals(num2)); //true
	}

在这里插入图片描述

equals源码

在这里插入图片描述

我们指定equal比较的是内容本身,并且我们也可以看到equal的参数是一个Object对象,我们传入的是一个int类型,所以首先会进行装箱,然后比较,之所以返回true,是由于它比较的是对象里面的value值

3、

public static void main(String[] args) {
		Integer num1 = 100;
		int num2 = 100;
		Long num3 = 200l;
		System.out.println(num1 + num2);  //200
		System.out.println(num3 == (num1 + num2));  //true
		System.out.println(num3.equals(num1 + num2));  //false
	}

在这里插入图片描述

1、当一个基础数据类型与封装类进行==、+、-、*、/运算时,会将封装类进行拆箱,对基础数据类型进行运算。
2、对于num3.equals(num1 + num2)为false的原因很简单,我们还是根据代码实现来说明:

在这里插入图片描述

它必须满足两个条件才为true:

  • 类型相同
  • 内容相同
    上面返回false的原因就是类型不同。

4、

public static void main(String[] args) {
		Integer num1 = 100;
		Integer num2 = 200;
		Long num3 = 300l;
		System.out.println(num3 == (num1 + num2)); //true
	}

在这里插入图片描述

在这里插入图片描述

可以看到运算的时候首先对num3进行拆箱(执行num3的longValue得到基础类型为long的值300),然后对num1和mum2进行拆箱(分别执行了num1和num2的intValue得到基础类型为int的值100和200),然后进行相关的基础运算。

基础类型的测试

public static void main(String[] args) {
		int num1 = 100;
		int num2 = 200;
		long num3 = 300;
		System.out.println(num3 == (num1 + num2)); //true
	}

在这里插入图片描述

总结

  1. 需要知道什么时候会引发装箱和拆箱
  2. 装箱操作会创建对象,频繁的装箱操作会消耗许多内存,影响性能,所以可以避免装箱的时候应该尽量避免。
  3. equals(Object o) 因为原equals方法中的参数类型是封装类型,所传入的参数类型(a)是原始数据类型,所以会自动对其装箱,反之,会对其进行拆箱
  4. 当两种不同类型用==比较时,包装器类的需要拆箱。
    当同种类型用
    ==比较时,会自动拆箱或者装箱

参考:https://www.cnblogs.com/wang-yaz/p/8516151.html

https://www.cnblogs.com/dolphin0520/p/3780005.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值