Java系统数据方面,分两种类型,一种是八大基本类型,包括 int long short 等,另一种是对象引用类型,如 String List 自定义的对象等等。八大基本类型都有一个对应的引用类型,称为装箱基本类型,例如 int double boolean 对应的装箱类型是 Interger Double Boolean。 Java 1.5 版本后,增加了自动装箱和自动拆箱功能,比如List里不能直接add() int类型,但自动装箱后, add(0)时,会自动把 int 装箱为 Interger ,0 由int类型变为了对象0,装进了List集合。基本类型和装箱基本类型有几点区别: 基本类型只有值,装箱基本类型不但有基本类型的值,它还有一个引用地址值,所以相同值的两个装箱基本类型的引用值可能不一样;装箱类型由于是对象,所以可能为 null;基本类型比装箱基本类型节省时间与空间。使用的时候一定要小心。举个例子,平常用于比较数据大小而进行排序,会用到Comparator,如果把 Interger 传进去,那么
void test(){
Comparator<Integer> naturalOrder = new Comparator<Integer>() {
public int compare(Integer first, Integer second) {
return first < second ? -1 : (first == second ? 0 : 1);
}
};
int compare = naturalOrder.compare(new Integer(42), new Integer(42));
System.out.println(compare);
}
猛一看,没问题,测试一下,发现打印的compare 值为1而非0,说明第一个Integer大于第二个Integer。为什么呢,first < second 这个比较比的是int值,但 first == second 这个比较的就不是 int 值了,而是比较的对象引用的地址值,由于这是两个不同的对象所以返回了false导致 compare 返回的是1,可见,装箱类型可以认为是对象,不同的对象有不同的地址值。上面代码修改,把Integer值转换为int值,再进行比较,就正确了。
void test1(){
Comparator<Integer> naturalOrder2 = new Comparator<Integer>() {
public int compare(Integer first, Integer second) {
int i = first;
int j = second;
return i < j ? -1 : (i == j ? 0 : 1);
}
};
int compare = naturalOrder2.compare(new Integer(42), new Integer(42));
System.out.println(compare);
}
由此引发另一个问题,如果说装箱基本类型有引用的话,如果没有赋值,直接使用会是什么情况呢?
static Integer i;
void test2(){
if(42 == i)
System.out.println("Unbelievable");
}
它没打印出Unbelievable,而是直接NullPointException了,为什么String和List等对象没初始化,进行 == 操作都没事,而这个出问题了呢? 原来 Integer 没有初始化,但 (i == 42) 时,会自动拆箱, 把 Integer 变为 int 类型进行比较,结果这时候对 null 做了拆箱,当然就 Exception in thread "main" java.lang.NullPointerException了。
之前提到一个性能问题,自动装箱比基本类型操作要消耗大得多
void test3(){
Long sum = 0L;
for(long i = 0; i < Integer.MAX_VALUE; i++) {
sum += i;
}
System.out.println(sum);
}
运行比较慢,是因为初始值 sum 为 Long类型,之后相加,都会自动装箱,所以明显的性能下降,因为反复的被装箱和拆箱。所以,慎用装箱基本类型。