Integer的存储
Integer是int的封装类,一般来说基础变量(int)赋值给Integer对象将自动装箱(Auto Boxing)并为Integer对象分配堆空间。因此即使基础变量值一样,封装类对象指向不同地址。
对JVM为了节省空间, 当Integer的值落在-128~127之间时,如Integer i1 = 2; Integer i2 = 2;此时JVM首先检查是否已存在值为2的Integer对象。如果是,则i2直接是引用已存在对象,即i2 = i1。
事实上, Integer已经默认创建了数值[-128~127]的Integer缓存数据。所以使用Integer i1=2时,JVM会直接在该在对象池找到该值的引用。
对于显式的new Integer(2),JVM将直接分配新空间。
因此,下列判断结果如下:
Integer a = 200;
Integer b = 200;
System.out.println(a==b); //false
Integer c = 1;
Integer d = 1;
Integer e = new Integer(1);
System.out.println(c==d); //true
System.out.println(d==e); //false;
int i = 1;如果在类中定义,就存放在堆,在方法中定义,就存放在栈(直接存放i=1)
自动拆箱与装箱
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对象。其内部变化如下
1
2 sum = sum.intValue() + i;
Integer sum = new Integer(result);
由于我们这里声明的sum为Integer类型,在上面的循环中会创建将近4000个无用的Integer对象,在这样庞大的循环中,会降低程序的性能并且加重了垃圾回收的工作量。因此在我们编程时,需要注意到这一点,正确地声明变量类型,避免因为自动装箱引起的性能问题。