在给部门做分享的时候,一位同学提问说一直没搞明白Java的装箱和拆箱,让我给讲解下,所以才有了下面这篇文章:

本次文章根据PPT分享整理而成,会有5点:

1、什么是装箱和拆箱?

2、基本数据类型和包装类型区别

3、示例演示

4、示例代码分析

5、总结

1、什么是装箱和拆箱?

概念:

装箱是将基本类型转换为包装类型

拆箱是想包装类型转换为基本类型

示例:

Integer a = new Integer(1); //装箱
int b = a.intVal(); //拆箱
//JDK1.5开始自动装箱和拆箱
Integer a = 1; //自动装箱
int b = a;//自动拆箱

2、基本数据类型和包装类型区别

概念:

基本数据类型:不需要在堆中分配内存,直接将变量的值存储在堆栈上

包装类型:基本数据类型不具有对象的性质,为了让其具有对象性质,故出现包装类型,将基本类型包装,使其具有对象性质

相互转换:

基本数据类型转换为包装类型

Integer.valueOf(int);
...

包装类型转换为基本数据类型

intValue();
longValue();
...

基本类型和包装类型对应关系

基本数据类型

包装类型

byte

Byte

char

Character

short

Short

int

Integer

long

Long

float

Float

double

Double

boolean

Boolean

3、示例演示

// 如果您能全部回答正确,您可以跳过后面章节:
public static void main(String[] args) {
Integer a = 1;
Integer b = 2;
Integer c = 3;
Integer d = 3;
Integer e = 129;
Integer f = 129;
Long g = 3L;
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(e.equals(f));
System.out.println(g == (a+b));
System.out.println(g.equals(a+b));
}

4、示例代码分析

// 反编译代码,注意:其中中文注释是我加的,便于大家查看
public static void main(java.lang.String[]);
Code:
0: iconst_1
1: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
4: astore_1
5: iconst_2
6: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
9: astore_2
10: iconst_3
11: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
14: astore_3
15: iconst_3
16: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
19: astore 4
21: sipush 129
24: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
27: astore 5
29: sipush 129
32: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
35: astore 6
37: ldc2_w #3 // long 3l
40: invokestatic #5 // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;
43: astore 7
45: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
48: aload_3
49: aload 4
51: if_acmpne 58 //c==d,注意这里执行进行了引用比较
54: iconst_1
55: goto 59
58: iconst_0
59: invokevirtual #7 // Method java/io/PrintStream.println:(Z)V
62: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
65: aload 5
67: aload 6
69: if_acmpne 76 //e==f,注意这里执行进行了引用比较
72: iconst_1
73: goto 77
76: iconst_0
77: invokevirtual #7 // Method java/io/PrintStream.println:(Z)V
80: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
83: aload_3
84: invokevirtual #8 // Method java/lang/Integer.intValue:()I
87: aload_1
88: invokevirtual #8 // Method java/lang/Integer.intValue:()I
91: aload_2
92: invokevirtual #8 // Method java/lang/Integer.intValue:()I
95: iadd // 这里执行了(a+b)
96: if_icmpne 103 // 这里执行c==(a+b),数值比较
99: iconst_1
100: goto 104
103: iconst_0
104: invokevirtual #7 // Method java/io/PrintStream.println:(Z)V
107: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
110: aload_3
111: aload_1
112: invokevirtual #8 // Method java/lang/Integer.intValue:()I //拆箱
115: aload_2
116: invokevirtual #8 // Method java/lang/Integer.intValue:()I //拆箱
119: iadd
120: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; //装箱
123: invokevirtual #9 // Method java/lang/Integer.equals:(Ljava/lang/Object;)Z //c.equals(a+b)
126: invokevirtual #7 // Method java/io/PrintStream.println:(Z)V
129: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
132: aload 5
134: aload 6
136: invokevirtual #9 // Method java/lang/Integer.equals:(Ljava/lang/Object;)Z //e.equals(f)
139: invokevirtual #7 // Method java/io/PrintStream.println:(Z)V
142: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
145: aload 7
147: invokevirtual #10 // Method java/lang/Long.longValue:()J //Long 拆箱
150: aload_1
151: invokevirtual #8 // Method java/lang/Integer.intValue:()I //Integer 拆箱
154: aload_2
155: invokevirtual #8 // Method java/lang/Integer.intValue:()I //Integer 拆箱
158: iadd // (a+b)
159: i2l // (a+b)结果转换为long类型
160: lcmp // 执行 g == (a+b) 数值比较
161: ifne 168
164: iconst_1
165: goto 169
168: iconst_0
169: invokevirtual #7 // Method java/io/PrintStream.println:(Z)V
172: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
175: aload 7
177: aload_1
178: invokevirtual #8 // Method java/lang/Integer.intValue:()I //Integer 拆箱
181: aload_2
182: invokevirtual #8 // Method java/lang/Integer.intValue:()I //Integer 拆箱
185: iadd // (a+b)数值相加
186: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; // Integer装箱
189: invokevirtual #11 // Method java/lang/Long.equals:(Ljava/lang/Object;)Z //执行g.equals(a+b)
192: invokevirtual #7 // Method java/io/PrintStream.println:(Z)V
195: return
}
结合反编译代码,给出的分析:
当我们定义Integer a = 1;时实际执行Integer.valueOf(1),返回Integer对象
// 默认IntegerCache.low = -128, IntegerCache.high = 127
// 但是可以指定"java.lang.Integer.IntegerCache.high"
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}

当我们给a、b、c和d赋值时,是在-128-127范围内,直接从缓存中取值,而执行e和f赋值时,会执行new Integer(int),所以他们是不同的Integer对象;

"=="符只有遇到运算符才会执行“自动拆箱”
当执行equals比较,会执行类型判断和数值比较
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}

运行结果

c == d:true //没有自动拆箱,直接比较引用
e == f:false //没有自动拆箱,直接比较引用
c == (a+b):true //执行“自动拆箱”,进行数值比较
c.equals(a+b):true //a+b拆箱相加,然后自动装箱,再执行equals
e.equals(f):true //没有执行装箱和拆箱
g == (a+b):true //自动拆箱,执行idd,进行数值比较
g.equals(a+b):false //a+b拆箱相加,然后自动装箱,再执行equals

5、总结

包装类型的数值比较,要注意"=="符号的使用,最好使用equals进行数值比较,因为equals会自动执行拆箱,进行数值比较