Java中有了基本类型为什么还需要包装类?

概述

Java中有8种基本数据类型,这些基本类型都有对应的包装类。

为什么

因为Java是一种面向对象语言,很多地方都需要使用对象而不是基本数据类型。比如,在集合类种,我们是无法将int、double等类型放进去的。因为集合的容器要求元素是Object类型。

为了让基本类型也具有对象的特征,就出现了包装类型,它相当于将基本类型“包装起来”,使得它具有了对象的性质,并且为其添加了属性和方法,丰富了基本类型的操作。

区别

  1. 默认值不同,基本类型的默认值为0,false或\u0000等,包装类默认为null
  2. 初始化方式不同,一个需要new,一个不需要
  3. 存储方式不同,基本类型保存在栈上,包装类对象保存在堆上,成员变量的话,在不考虑jit优化的栈上分配时,都是随着对象一起保存在堆上的

自动拆装箱

包装类是对基本类型的包装,所以把基本数据类型转换成包装类的过程就是装箱;反之,把包装类转换成基本数据类型的过程就是拆箱。

在Java SE5中,为了减少开发人员的工作,Java提供了自动拆箱与自动装箱功能。

如:int的自动装箱都是通过Integer.valueOf()方法来实现的,Integer的自动拆箱都是通过Integer.intValue()来实现的。

自动拆装箱的场景

场景一:将基本数据类型放入集合类

Java集合类只能接收对象类型,那么以下代码为什么会不报错呢?

List<Integer>li new ArrayList<>();
for (int i=1;i<50;i++{
    1i.add(i);
}

将上面代码反编译,得到以下代码:

List<Integer>li new ArrayList<>();
for (int i=1;i<50;i++{
    1i.add(Integer.valueOf(i));
}

所以当我们把基恩数据类型放入集合类重,会进行自动装箱

场景二:包装类型和基本数据类型的大小比较

有没有人想过,当我们怼Integer对象与基本类型进行大小比较的时候,实际上比较的是什么内容呢?看以下代码:

Integer a=1;
System.out.println(a==1?"等于":"不等于");// 等于
Boolean bool=false;
System.out.print1n(bool?"真":"假");// 真

反编译之后:

Integer a=1;
System.out.println(a.intValue()==1?"等于":"不等于");// 等于
Boolean bool=false;
System.out.print1n(bool.booleanValue?"真":"假");// 真

可以看到,包装类和基本数据类型进行比较运算,是先将包装类进行拆箱成基本数据类型再进行比较的

场景三:包装类型的运算

对Integer进行四则运算

Integer i 10;
Integer j=20;
System.out.println(i+j);

反编译之后

Integer i=Integer.valueOf(10);
Integer j=.valueOf(20);
System.out.println(i.intValue()+j.intValue());

可以发现,两个包装类型之间运算,会被自动拆箱成基本类型进行四则运算

场景四:三目运算符的使用

这是很多人不知道的一个场景,严重的可以造成线上生产事故,看一个简单的三目运算符的代码:

boolean flag=true; //设置成true,保证条件表达式的表达式二一定可以执行
boolean simpleBoolean=false; //定义一个基本数据类型的boolean变量
Boolean nullBoolean=null;//定义一个包装类对象类型的Boolean?变量,值为nul1
boolean x =f1ag?nullBoolean:simpleBoolean;//使用三目运算符并给x变量赋值

在最后一行,右边会发生自动拆箱,反编译后:

boolean flag=true; //设置成true,
boolean simpleBoolean=false;
Boolean nullBoolean=null;
boolean x =f1ag?nullBoolean.booleanValue():simpleBoolean;

这其实是三目运算符的语法规范。当第二、第三位操作数分别为基本类型和对象时,编译器会将其中的包装类对象就自动拆箱为基本类型进行操作。因此 null.booleanValue()会造成npe异常。

场景五:函数参数与返回值

上代码:

//自动拆箱
public int getNum1(Integer num){
return num;
}
//自动装箱
public Integer getNum2(int num){
return num;
}

自动拆装箱和缓存

Java SE的自动拆装箱还提供了一个和缓存有关的功能,我们先来看以下代码

public static void main(String...strings){
    Integer integer1 = 3;
    Integer integer2 = 3;
    if (integer1 == integer2)
        System.out.println("integer1 == integer2"); // 执行这段
    else
        System.out.println("integer1 != integer2);
    Integer integer3 = 300;
    Integer integer4 = 300;
    if (integer3 == integer4)
        System.out.println("integer3 == integer4");
    else
        System.out.println("integer3 != integer4"); // 执行这段
}

原因是Integer中的暖存机制导致,在Java5中,Integer引入了一个新功能来节省内存和提高性能。整型对象通过使用相同的对象引用实现了缓存和重用。

Integer缓存区间  -128~+127, 在此区间会直接使用缓存中的对象,而不会重新创建对象

只适用于自动装箱,使用构造函数创建对象不适用,比如new

其中javadoc详细的说明了缓存支持-128到127之间的自动装箱支持,最大值127可以通过 -XX:AutoBoxCacheMax=size 修改。 在Java6中也可以通过java.lang.Integer.IntegerCache.high 设置最大值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值