java unbox_Java中Auto Box/Unbox容易踩到的“坑”,Integer

Java中的Auto Box/Unbox对写代码带来了便利性,但也挺容易就踩进“坑”里,主要是NPE,对象比较还有内存浪费。

自动装箱、拆箱

先解释下什么是自动装箱、拆箱,基本数据类型的自动装箱(autoboxing)、拆箱(unboxing)是自J2SE 5.0开始提供的功能。

这是最典型的Auto Box/Unbox的代码:

Integer i = 100;

int j = i;

一般我们要创建一个类的对象实例的时候,我们会这样:Class a = new Class(parameter);

当我们创建一个Integer对象时,却可以这样:Integer i = 100; (注意:不是 int i = 100; )

实际上,执行上面那句代码的时候,系统为我们执行了:Integer i = Integer.valueOf(100);

此即基本数据类型的自动装箱功能。自动拆箱则与其相反,int t = i; //拆箱,实际上执行了int t = i.intValue();

注:在运算时,也可以自动拆箱(System.out.println(i++);//i是Integer类型)

易入坑

Auto Box/Unbox在有些场景下容易产生NPE,例如假设有一个这样的方法:

public void execute(int code){}

假设调用方是从一个Map或其他地方获取到的Integer,如果忘记判断是否为null,直接传给execute的方法,就有可能导致NPE。

下面这个关于Integer的Case也是比较常见的:

Integer i = 100;

Integer j = 100;

Integer m = 200;

Integer n = 200;

System.out.println(i == j);

System.out.println(m == n);

其执行结果为:true,false

原因是Integer会cache -127~127的Integer对象,而不在这个范围的则会每次new Integer。

在JavaOne 2010大会上,还有一段关于Auto Box/Unbox带来的频繁YGC的案例代码,代码的关键信息如下:

public class A{

private int code;

public A(int code){

this.code = code;

}

public int get(){

return code;

}

}

public class Demo{

public statice void main(String[] args) throws Exception{

Map map = new HashMap();

// 往map里放1w个从1开始的A对象

...

while(true){

Collection values = map.values();

for(A a: values){

if(!map.containsKey(a.getId())){

// 不可能发生,所以可以随便打点什么

}

Thread.sleep(1);

}

}

}

}

在上面的代码中,其实只需要把A中的private int code和public int get中的int改为Integer,就可以避免频繁的YGC,因此在写代码时还是要稍微注意下Auto Box/Unbox带来的影响。

例子

通过下面的代码例子说明包装类:

public class Main {

public static void main(String[] args) {

Integer a = 1;

Integer b = 2;

Integer c = 3;

Integer d = 3;

Integer e = 321;

Integer f = 321;

Long g = 3L;

Long h = 2L;

System.out.println(c==d);

System.out.println(e==f);

System.out.println(c==(a+b));

System.out.println(c.equals(a+b));

System.out.println(g==(a+b));

System.out.println(g.equals(a+b));

System.out.println(g.equals(a+h));

}

}

看下输出结果:

true

false

true

true

true

false

true

当 “==”运算符的两个操作数都是 包装器类型的引用,则是比较指向的是否是同一个对象,而如果其中有一个操作数是表达式(即包含算术运算)则比较的是数值(即会触发自动拆箱的过程)。另外,对于包装器类型,equals方法并不会进行类型转换。

第一个和第二个输出结果没有什么疑问。第三句由于  a+b包含了算术运算,因此会触发自动拆箱过程(会调用intValue方法),因此它们比较的是数值是否相等。而对于c.equals(a+b)会先触发自动拆箱过程,再触发自动装箱过程,也就是说a+b,会先各自调用intValue方法,得到了加法运算后的数值之后,便调用Integer.valueOf方法,再进行equals比较。同理对于后面的也是这样,不过要注意倒数第二个和最后一个输出的结果(如果数值是int类型的,装箱过程调用的是Integer.valueOf;如果是long类型的,装箱调用的Long.valueOf方法)。

相关函数

通过学习Integer肯定要对以下三个函数产生困惑,valueof、parseInt、intValue,下面进行一一介绍

Integer.valueof()返回的是Integer的对象

初始化为指定 String /Int值的新的 Integer 对象。若该 String 不能作为 int 分析,则抛出异常。自动包装调用的函数,注意返回值是Integer

Integer.parseInt() 返回的是一个int的值

它的作用就是将形参 s 转化为整数,注意返回值是int

Integer.valueof().intValue();返回的也是一个int的值。

自动拆包调用的函数,注意返回值是int

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值