0%

浅谈拆包装包

关于拆包装包这块,以前一直是一知半解,也觉得没有什么需要特别写出来的必要,反正是 JAVA 自带的性质。
最近发现里面还是有一些以前不曾在意的机制的,简单说一下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public static void main(String[] args) {
System.out.println(new Integer(1) == new Integer(1)); //1

System.out.println(new Integer(1) == 1); //2

System.out.println(new Integer(1) + new Integer(1) == 2); //3

Integer a = 1;
Integer b = 1;
System.out.println(a==b); //4

Integer a1 = 128;
Integer b1 = 128;
System.out.println(a1==b1); //5

int a2 = new Integer(1236);
Integer b2 = new Integer(1236);
System.out.println(a2==b2); //6

}
可以得到结果:
false //1
true //2
true //3
true //4
false //5
  1. 因为自动装包机制,a 和 b 实际指向的是对象的内存地址。而两个 new 出来的对象地址一定不相等
  2. 因为自动拆包机制,当包装类型与基础类型比较时,会进行拆包,对基础类型的值进行比较,所以相等
  3. 当包装类型进行计算时,会进行自动拆包,故比较的是值,而不是地址,为true。
  4. 因为基础类型的缓存机制,int类型会缓存[-128,127]的值,int a = 1,实际上是类似于调用了 int a = Integet.valueOf(1),如果缓存中存在,则会直接返回该对象,并不会new,所以同一个对象的内存引用地址一样,故相等
  5. 同上,只是128超出了缓存的范围,因此是new出来的,所以两个对象引用地址不同。
  6. 声明时是 int, int a2 = new Integer(1236) 实际上是 int a2 = new Integer(1236).intValue(); 且当包装类型与基础类型比较时,会自动拆表比较值。

根据自身理解,自动拆包有一下几种情况:

  1. 当存在算术符号时
  2. 当包装类型与基础类型比较时
  3. 声明对象时使用基础类型声明时

自动包装有以下几种情况:

  1. 声明对象为包装类型时,包括new,和直接给定值。区别在于,new的时候一定是一个新的对象,而后者通常调用了XXX.valueOf(a),有可能会从缓存中直接获取。
    • int a = new Integer(1);
    • int a = 1;

更详细的文档请看: https://docs.oracle.com/javase/tutorial/java/data/autoboxing.html

Tips

包装类型缓存范围如下:

类型 范围
Byte,Short,Integer,Long [-128,127]
Character [0,127] 前128个字符
Boolean true,false
Float, Double 无缓存