自动装箱和拆箱是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。
这下明白了吧?