简介
说明
本文介绍Java的基本类型知识,包括:拆箱与装箱、实例化顺序、区域问题、缓存问题、效率问题。
为什么基本类型需要包装类
- 基本数据类型方便、简单、高效,但泛型不支持、集合元素不支持
- 不符合面向对象思维
- 包装类提供很多方法,方便使用,如 Integer 类 toHexString(int i)、parseInt(String s) 方法
Long或Integer如何比较大小?
- 错误方法
- 使用==。 因为Long与Ineger都是包装类型,是对象。 而不是普通类型long与int
- 使用equals方法。因为equals方法只能比较同类型的类,例如两个都是Integer类型。
- 正确方法
- 先使用longValue()或intValue()方法来得到他们的基本类型的值然后使用==比较也是可以的。
拆箱与装箱原理

装箱就是将基本数据类型转化为包装类型,那么拆箱就是将包装类型转化为基本数据类型。
实例1:查看反汇编文件
package org.example.a;
public class Demo{
public static void main(String[] args) {
//自动装箱,底层其实执行了Integer a=Integer.valueOf(10);
Integer a = 10;
//自动拆箱,底层其实执行了int b=a.intValue();
int b = a;
}
}
生成并查看反汇编文件
依次执行如下命令
javac -d . org\example\a\Demo.java javap -c org.example.a.Demo
输出结果如下(没有任何手动添加内容(//xxx都是自己生成的)):
E:\work\idea_proj\test_java\src>javap -c org.example.a.Demo
Compiled from “Demo.java”
public class org.example.a.Demo {
public org.example.a.Demo();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object.”<init>”:()V
4: returnpublic static void main(java.lang.String[]);
Code:
0: bipush 10
2: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
5: astore_1
6: aload_1
7: invokevirtual #3 // Method java/lang/Integer.intValue:()I
10: istore_2
11: return
}
Integer a = 10;
执行上面那句代码的时候,系统为我们执行了:Integer a = Integer.valueOf(10);
int b = a;
执行上面那句代码的时候,系统为我们执行了:int b = a.intValue();
实例:自动拆装箱
实例1:基本类型与其包装类
package org.example.a;
public class Demo {
public static void main(String[] args) {
int int1 = 12;
int int2 = 12;
Integer integer1 = new Integer(12);
Integer integer2 = new Integer(12);
System.out.println("int1 == int2 : " + (int1 == int2));
System.out.println("int1 == integer1 : " + (int1 == integer1));
System.out.println("integer1 == integer2 : " + (integer1 == integer2));
}
}
运行结果
int1 == int2 : true int1 == integer1 : true integer1 == integer2 : false
Integer是int的封装类,当Integer与int进行==比较时,Integer就会拆箱成一个int类型,所以还是相当于两个int类型进行比较,这里的Integer不管是直接赋值,还是new创建的对象,只要跟int比较就会拆箱为int类型,所以就是相等的。
实例2:自动拆箱引起的异常
首先思考,下边的程序会输出什么
package com.example.a;
public class Demo {
public static void main(String[] args) {
Integer a = null;
System.out.println(2 == a);
}
}
结果
Exception in thread "main" java.lang.NullPointerException at com.example.a.Demo.main(Demo.java:6)
原因:
因为是基本类型与包装类型进行比较,此时会将包装类型自动拆箱,调用a.intValue()获得其基本类型的值,但a是null,所以报空指针异常。
实例3:基本类型与Object
package org.example.a;
public class Demo {
public static void main(String[] args) {
Object object = true;
System.out.println(object);
boolean b = (boolean)object;
System.out.println(b);
System.out.println(b == true);
}
}
运行结果
true true true
实例:实例化顺序
package org.example.a;
public class Demo {
public static void main(String[] args) {
int int1 = 12;
Integer integer1 = new Integer(12);
Integer integer2 = new Integer(34);
int int2 = 34;
System.out.println("int1 == integer1 : " + (int1 == integer1));
System.out.println("int2 == integer2 : " + (int2 == integer2));
}
}
执行结果(不影响)
int1 == integer1 : true int2 == integer2 : true
实例:区域问题
package org.example.a;
public class Demo {
public static void main(String[] args) {
Integer integer1 = new Integer(12);
Integer integer2 = 12;
System.out.println("integer1 == integer2 : " + (integer1 == integer2));
}
}
执行结果
integer1 == integer2 : false
实例:缓存问题
测试代码
package org.example.a;
public class Demo{
public static void main(String[] args) {
Integer a = 127;
Integer b = 127;
Integer c = 128;
Integer d = 128;
System.out.println(a == b);
System.out.println(c == d);
}
}
执行结果
true false
原因
Integer有个缓存,原理如下。
valueOf源码
//private static class IntegerCache {
// static final int low = -128;
// static final int high = 127;
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
当i的值位于[-128,127]的时候,会直接返回Integer缓存数组中相应对象的引用,如果i大于127或小于-128,会重新创建一个Integer实例,并返回。
那么第一条式子a和b的值都在缓存范围内,因此他们指向同一个对象,因此返回true。c和d的值不在范围内,都是通过new创建出来的,因此不是同一个对象,返回false。
其他包装类的缓存
Byte、Short、Integer、Long、Character的valueOf()实现机制类似。
| 包装类 | 说明 |
| Byte | 相同值的Byte比较永远返回true。因为byte取值范围就是[-128,127]。 |
| Short、Integer、Long | 相同值在[-128,127]则返回true,不在则返回false |
| Character | 要返回true,只需保证i <= 127。因为char最小值为0,本来就大于等于-128。 |
| Float、Double | 永远返回false。因为其永远返回新创建的对象,因为一个范围内的整数是有限的,但是小数却是无限的,无法保存在缓存中。 |
| Boolean | 只有两个对象,要么是true的Boolean,要么是false的Boolean,只要boolean的值相同,Boolean就相等。 |
实例:效率问题
package org.example.a;
public class Demo {
public static void main(String[] args) {
long t1 = System.currentTimeMillis();
Long sum = 0L;
for (int i = 0; i < Integer.MAX_VALUE; i++) {
sum += i;
}
long t2 = System.currentTimeMillis();
System.out.println(t2 - t1);
}
}
上述代码,结果为:6218
如果将sum改为long型,结果为:624
可见效率差别之大

请先 !