自动装箱与拆箱

概念

自动装箱:就是自动将基本数据类型包装为包装器类型;

自动拆箱:就是自动将包装器类型转换为基本数据类型;

1
2
Interger i = 1; // 拆箱
int n = i; // 装箱

这个装箱拆箱操作是jdk5的新特性

  • JDK5之前的方式:比如Integer i = Integer.valueof(5);(这里5为基本类型int,Integer包装类利用valueof()方法将其转换为Integer类型)或者int i = i.intValue();(这里基本类型利用intValue()方法将Integer类型转换为基本类型int)。
  • JDK5之后的方式:比如①Integer i = 5;或者②int i = new Integer(100);,这里基本类型与包装类之间可直接操作,而①的操作就是自动装箱,②的操作就是自动拆箱。
More Actions 默认值 存储需求(字节) 取值范围 示例 包装类型
byte 0 1 -2^7—2^7-1 byte b=10; Byte
char ‘ \u0000′ 2 0—2^16-1 char c=’c’ ; Character
short 0 2 -2^15—2^15-1 short s=10; Short
int 0 4 -2^31—2^31-1 int i=10; Integer
long 0 8 -2^63—2^63-1 long o=10L; Long
float 0.0f 4 -2^31—2^31-1 float f=10.0F Float
double 0.0d 8 -2^63—2^63-1 double d=10.0; Double
boolean false 不确定 true\false boolean flag=true; Boolean

boolean的大小java规范并没有明确给出具体查看:

https://www.cnblogs.com/wangtianze/p/6690665.html

例题

1、有如下4条语句:()

1
2
3
4
Integer i01=59;
int i02=59;
Integer i03=Integer.valueOf(59);
Integer i04=new Integer(59);

以下输出结果为false的是:

  • System.out.println(i01==i02);
  • System.out.println(i01==i03);
  • System.out.println(i03==i04);
  • System.out.println(i02==i04);
查看答案 答案:D

解析:

  • 无论如何,Integer与new Integer不会相等。不会经历拆箱过程。
  • 两个都是非new出来的Integer,如果数在-128到127之间,则是true,否则为false;java在编译Integer i2 = 128的时候,被翻译成-> Integer i2 = Integer.valueOf(128);而valueOf()函数会对-128到127之间的数进行缓存。

Integer.valueOf方法中也有判断,如果传递的整型变量>= -128并且小于127时会返回IntegerCache类中一个静态数组中的某一个对象, 否则会返回一个新的Integer对象,代码如下

1
2
3
4
5
6
public static Integer valueOf(int i) {
assert IntegerCache.high >= 127;
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.[i + (-IntegerCache.low)];
return new Integer(i);
}
  • 两个都是new出来的,都为false
  • int和integer(无论new否)比,都为true,因为会把Integer自动拆箱为int再去比

我认为理论看的再多也不如实际的去做题,理论知道的多,题目不一定做得对,做题可以巩固自己的理论知识。

2、下面程序的输出结果是什么?(这个是我引用参考链接中第二个链接中的一个例子)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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); // 1
System.out.println(e==f); // 2
System.out.println(c==(a+b)); // 3
System.out.println(c.equals(a+b)); // 4
System.out.println(g==(a+b)); // 5
System.out.println(g.equals(a+b)); // 6
System.out.println(g.equals(a+h)); // 7
}
}
查看答案 答案:1.true 2.false 3.true 4.true 5.true 6.false 7.true

解析:

  1. c==d:因为Integer中缓存的存在,如果数在[-128,127] (包括边界),则是true,否则为false
  2. e==f:同1
  3. c=(a + b):a + b 这个操作会自动拆箱结果为int
  4. c.equals(a+b):无需解释
  5. (g==(a+b)):同3 a+b=> int g为Long自动拆箱为long 然后int类型自动提升为long
  6. g.equals(a+b):a+b 为int 类型,Long 与 相同值的 包装类 用equals比较时,如果传入的类型不是Long,那么全部返回false,Long类中的equals()源码:

  1. g.equals(a+b):true a+h 结果会向精度大的转换 为long类型

总结

比较值

  1. 基本数据类型与引用数据类型进行比较时,引用数据类型会进行拆箱,然后与基本数据类型进行值的比较

int i = 12;
Integer j = new Integer(12);
i == j 返回的是true

二、引用数据类型与基本数据类型进行比较(equals方法),基本数据类型会进行自动装箱,与引用数据类型进行比较,Object中的equals方法比较的是地址,但是Integer类已经重写了equals方法,只要两个对象的值相同,则可视为同一对象,具体看API文档,所以这归根到底也是值的比较!

int i = 12;
Integer j = new Integer(12);
j.equals(i) 返回的是true

比较地址

  1. 如果引用数据类型是这样 Integer i = 12;直接从常量池取对象,这是如果数值是在-128与127之间,则视为同一对象,否则视为不同对象

Integer i = 12; Integer j = 12; i == j 返回的是true
Integer i = 128; Integer j = 128; i == j 返回的是false

  1. 如果引用数据类型是直接new的话,不管值是否相同,这时两个对象都是不相同的,因为都会各自在堆内存中开辟一块空间

Integer i =new Integer(12);
Integer j = new Integer(12);
i == j 这时返回的是false

  1. 从常量池取对象跟new出来的对象也是不同的

举例:
Integer i = 12; // 这个常量池中的
Integer j = new Integer(12) // 这个是堆中创建的
i == j 这时返回的是false

参考

https://www.cnblogs.com/wang-yaz/p/8516151.html

https://www.cnblogs.com/dolphin0520/p/3780005.html

这两篇文章从源码以及jvm分析了原理,并且写的很好,我就不再说明了。