一般来说基础变量(int)赋值给Integer对象将自动装箱(Auto Boxing)并为Integer对象分配堆空间。因此即使基础变量值一样,封装类对象指向不同地址。
对JVM为了节省空间, 当Integer的值落在-128~127之间时,如Integer i1 = 2; Integer i2 = 2;此时JVM首先检查是否已存在值为2的Integer对象。如果是,则i2直接是引用已存在对象,即i2 = i1。所以System.out.println(“i1 = i2? ” + (i1 == i2)); //true
事实上,Integer已经默认创建了数值[-128~127]的Integer缓存数据。所以使用Integer i1=2时,JVM会直接在该在对象池找到该值的引用。
对于显式的new Integer(2),JVM将直接分配新空间。所以System.out.println(“i1 = i3? ” + (i1 == i3)); //false
自动拆箱与装箱
Integer、Long、Double这些包装类是final修饰的,不能被继承。Integer对象是不可变的,函数传递参数时,在函数内部修改,不会影响外部。
ArrayList(底层是object数组),需要传入对象,而不能直接传入int,所以有了Integer包装类,而在list.add(3)时,会自动装箱成为Integer。int n = list.get(i)会自动拆箱。
Integer.valueOf()底层就是new Integer(num),判断两个int可以用==,但判断两个Integer不能用==,需要用equals,就算是Integer a = new Integer(1); Integer b = new Integer(1); a==b也会输出false;Integer i1 = 2; Integer i2 = 2;i1==i2会输出true。
自动装箱的弊端
自动装箱有一个问题,那就是在一个循环中进行自动装箱操作的情况,如下面的例子就会创建多余的对象,影响程序的性能。
Integer sum = 0;
for(int i=1000; i<5000; i++){
sum+=i;
}
上面的代码sum+=i可以看成sum = sum + i,但是+这个操作符不适用于Integer对象,首先sum进行自动拆箱操作,进行数值相加操作,最后发生自动装箱操作转换成Integer对象。其内部变化如下
sum = sum.intValue() + i;
Integer sum = new Integer(result);
由于我们这里声明的sum为Integer类型,在上面的循环中会创建将近4000个无用的Integer对象,在这样庞大的循环中,会降低程序的性能并且加重了垃圾回收的工作量。