前言:
当前大家对“装箱问题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语言代码