龙空技术网

Java自动装箱和拆箱

程序员小潘 205

前言:

当前大家对“装箱问题c语言代码”大致比较关怀,同学们都想要学习一些“装箱问题c语言代码”的相关知识。那么小编也在网摘上搜集了一些有关“装箱问题c语言代码””的相关知识,希望小伙伴们能喜欢,咱们一起来了解一下吧!

基本类型和包装类型

Java是一种强类型的语言,这就意味着必须为每一个变量声明一种类型。

在Java中,一共有8种基本数据类型,且每个基本数据类型都含有对应的包装类型,对应关系如下表:

基本类型

包装类型

byte

Byte

short

Short

int

Integer

long

Long

float

Float

double

Double

boolean

Boolean

char

Character

1、为什么要有基本类型?

首先,基本类型不是一个Object,数值直接保存在栈中,不会在堆中开辟内存,也不存在Java对象的内存布局:对象头、对齐字节等数据,因此更加节省内存。

正是由于基本类型不是对象,没有对象头,所以在Java中基本类型不能用作锁对象。

包装类型实例存储在堆中,需要通过栈中的Reference引用来寻址找到对象才能访问。而基本类型数据存储在栈中,数据的读写效率更高,避免了对象寻址的过程。

2、为什么要有包装类型?

有了基本数据类型,为什么还要有包装类型?是不是多此一举呢?

Java是一门面向对象编程的语言,基本类型不是对象,不符合面向对象编程的特征。

包装类型通过将基本类型“包装”起来,使其具有了对象的性质,丰富了基本类型的操作,例如可以调用hashCode等方法了。

基本类型不允许为NULL,但是实际场景有需要为NULL的需求,如RPC调用,包装类型就可以满足。

泛型的需要,泛型要求包容的是对象类型,而基本类型不是对象,无法用作泛型。

3、基本类型和包装类型的区别?

基本类型不是对象,包装类型实例是对象。基本类型存储在栈中,包装类型实例存储在堆中。基本类型不能用作锁对象,包装类型可以。基本类型不允许为NULL,包装类型可以。基本类型不能用作泛型,包装类型可以。自动装箱和拆箱

基本数据类型和包装类之间可以自动地相互转换。

自动装箱就是将基本类型转换为包装类型。

自动拆箱就是将包装类型转换为基本类型。

如下代码,就是int和Integer的自动装箱和拆箱。

// 自动装箱Integer a = 10;// 自动拆箱int b = a;

实际上,底层执行代码是:

// 自动装箱Integer a = Integer.valueOf(10);// 自动拆箱int b = a.intValue();

自动装箱和拆箱的的特性,弱化了基本类型和包装类型的区别,以至于开发者稍有不慎,就掉进坑里。

自动装箱和拆箱的坑

1、空指针异常

自动拆箱的本质,其实就是调用了包装类实例的***Value()方法来获取基本类型的值。

如果包装类实例为NULL,自动拆箱就会导致空指针异常。

public class AutoWrapper {	public static void main(String[] args) {		if (func()) {			System.out.println("true");		}	}	static Boolean func(){		return null;	}}Exception in thread "main" java.lang.NullPointerException	at top.javap.box.AutoWrapper.main(AutoWrapper.java:13)

2、频繁创建对象

自动装箱的本质,其实就是调用了包装类的静态方法valueOf()来实例化对象。

如果使用不当,例如在循环中使用了包装类,就会导致JVM创建大量的包装类对象,导致频繁GC,影响系统的性能。

public class AutoWrapper {	public static void main(String[] args) {		for (int i = 0; i < Integer.MAX_VALUE; i++) {			//没有创建Integer实例		}				for (Integer i = 0; i < Integer.MAX_VALUE; i++) {			//创建了21亿个Integer实例,导致频繁GC		}	}}

笔者实测:堆内存100M,使用基本类型没有触发GC,使用包装类型触发了1026次Young GC。

Boolean的自动装箱不会导致频繁创建对象,因为Boolean内部维护了两个静态常量TRUE和FALSE,会不断复用这两个对象。Integer内部也维护了-128~127的缓存实例,这个区间的int自动装箱也不会再创建对象了。

3、==问题

自动装箱会让开发者对“==”比较两个对象是否相等的问题上产生疑惑。

	public static void main(String[] args) {		Integer a = 1;		Integer b = 1;		Integer c = 1000;		Integer d = 1000;		Boolean e = true;		Boolean f = true;	}

如上代码,a == b、c != d、e == f。这个结果可能会让开发者感到疑惑。

a == b是因为Integer内部维护了-128~127的缓存实例,1复用的是同一个Integer对象,所以是相等的。

c != d是因为1000超过了Integer的缓存,所以JVM会创建两个Integer对象,两个不同的对象肯定不相等嘛。

e == f是因为Boolean内部维护了TRUE和FALSE两个常量实例,所有的Boolean装箱都是复用的这两个对象,因此相等。

其他例子这里就不一一列举了,大家可以自己试一下。

标签: #装箱问题c语言代码