首页 > 代码库 > java自动装箱的陷阱

java自动装箱的陷阱

自动装箱和拆箱是java的一颗语法糖,在给我们带来使用便利的同时也带来一些疑惑,请看下面的代码:

 1 public class TestClass {
 2     public static void main(String args[]) {
 3         Integer a = 1;
 4         Integer b = 2;
 5         Integer c = 3;
 6         Integer d = 3;
 7         Integer e = 321;
 8         Integer f = 321;
 9         Long g = 3L;
10         
11         System.out.println(c == d);
12         System.out.println(e == f);
13         System.out.println(c == (a+b));
14         System.out.println(c.equals(a+b));
15         System.out.println(g == (a+b));
16         System.out.println(g.equals(a+b));
17     }
18 }

大家看一下上面这段代码的输出结果应该是什么?


答案是:

T

F

T

T

T

F


这样的答案是不是出乎很多人的意料呢?我们一一来分析。

1. 首先我们明确一下"=="和equals方法的作用。

  "==":如果是基本数据类型,则直接对值进行比较,如果是引用数据类型,则是对他们的地址进行比较

  equals方法继承自Object类,在具体实现时可以覆盖父类中的实现。看一下Object中qeuals的源码发现,它的实现也是对对象的地址进行比较,此时它和"=="的作用相同。而JDK类中有一些类覆盖了oject类的equals()方法,比较规则为:如果两个对象的类型一致,并且内容一致,则返回true,这些类有:
java.io.file,java.util.Date,java.lang.string,包装类(Integer,Double等)。

2. java的常量池技术。java中的基本类型的包装类、其中Byte、Boolean、Short、Character、Integer、Long实现了常量池技术,(除了Boolean,都只对小于128的值才支持)。什么意思呢?对于范围在-128到127大小的数据,java会在常量池中提前生成这个范围的数据,只要是指向这些数据的包装类,都有相同的地址。而不在这个范围内的数据会到堆上new一个出来。

3. "=="在遇到算术运算符的情况下不会自动拆箱,以及他们的equals方法不处理数据类型转换的关系。

 

因此,对于 System.out.println(c == d); 他们指向常量池中同一个地址,返回True。

对于 System.out.println(e == f); 他们的值大于127,即使值相同,但是对应不同的内存地址,返回false。

对于 System.out.println(c == (a+b)); 他们指向常量池中同一个地址,返回True。

对于 System.out.println(c.equals(a+b)); 他们的值相同,而且类型相同,返回true。

对于 System.out.println(g == (a+b)); 他们指向常量池中同一个地址,返回True。

对于 System.out.println(g.equals(a+b)); 他们的值相同但是类型不同,返回false。

这下明白了吧?

 

java自动装箱的陷阱