包装类的概述:
java中有8个基本类型:byte,short,int,long,float,double,char,boolean。它们是以值的形式存在于内存中,而不是对象。它们不是Object的子类,不能参与面向对象的开发。
若想将基本类型以对象的形式存在,就需要将它定义成一个类,然而java给八大基本数据类型提供相应的包装类:
byte java.lang.Byte
short java.lang.Short
int java.lang.Integer
long java.lang.Long
float java.lang.Float
double java.lang.Double
char java.lang.Character
boolean java.lang.Boolean
其中除了Character与Boolean的父类是Object之外,其余的都是继承自:java.lang.Number
自动装箱和自动拆箱操作(JDK1.5后的特性)
当我们需要将基本类型转换为包装类时,我们可以调用包装类的一个静态方法valueOf():
Integer i = Integer.valueOf(1);
Double d = Double.valueOf(1.1);
.......
当我们需要将包装类转换为基本类型时,我们可以使用包装类的方法xxxValue()方法(这里不同的包装类方法名不完全一致,但都是以Value结尾):
Integer i = new Integer(1);
int n = i.intValue();
....
虽然我们可以通过上述的方法在基本类型与包装类之间相互转换。但是在实际编写代码时相对还是比较麻烦的。java在1.5版本后推出了一个新的特性:自动拆装箱。
//可以自动将包装类转换为基本类型 自动拆箱
int i = new Integer(1);
//可以自动将基本类型转换成包装类 自动装箱
Integer in = 1;
java自动拆装箱的原理
事实上JVM不支持该特性,自动拆装箱只是编译器在编译过程中的"预处理"操作。编译器在看到需要在包装类与基本类型之间转换时,会在编译为字节码时进行改变:
源代码中 编译后的字节码中
Integer a = 100 => Integer a = Integer.valueOf(100);
Integer b = 200 => Integer b = Integer.valueOf(200);
Integer c = a+b => Integer c = Integer.valueOf (a.intValue( ) + b.intValue( ));
double d = c => double d = c . doubleValue( );
创建对象时涉及到常量池的问题
Integer i1 = 40;
Integer i2 = 40;
Integer i3 = 0;
Integer i4 = new Integer(40);
Integer i5 = new Integer(40);
Integer i6 = new Integer(0);
Integer i7 = 200;
Integer i8 = 200;
System.out.println("i1=i2\t" + (i1 == i2)); //true
System.out.println("i1=i2+i3\t" + (i1 == i2 + i3)); //true
System.out.println("i4=i5\t" + (i4 == i5)); //false
System.out.println("i4=i5+i6\t" + (i4 == i5 + i6)); //true
System.out.println("i7=i8\t" + (i7 == i8)); //false
Integer内部的源码:
public static Integer valueOf(int i) {
final int offset = 128;
if (i >= -128 && i <= 127) { // must cache
return IntegerCache.cache[i + offset];
}
return new Integer(i);
}
static {
for(int i = 0; i < cache.length; i++)
cache[i] = new Integer(i - 128);
}
Integer.valueOf()中有个内部类IntegerCache(类似于一个常量数组,也叫对象池),它维护了一个Integer数组cache,长度为(128+127+1)=256;Integer类中还有一个Static Block(静态块)
从这个静态块可以看出,Integer已经默认创建了数值【-128-127】的Integer缓存数据。所以使用Integer i1=40时,JVM会直接在该在对象池找到该值的引用。
也就是说这种方式声明一个Integer对象时,JVM首先会在Integer对象的缓存池中查找有木有值为40的对象,如果有直接返回该对象的引用;如果没有,则使用New keyword创建一个对象,并返回该对象的引用地址。因为Java中【==】比较的是两个对象是否是同一个引用(即比较内存地址),i2和i2都是引用的同一个对象,So i1==i2结果为”true“;而使用new方式创建的i4=new Integer(40)、i5=new Integer(40),虽然他们的值相等,但是每次都会重新Create新的Integer对象,不会被放入到对象池中,所以他们不是同一个引用,输出false。
对于i1==i2+i3、i4==i5+i6结果为True,是因为,Java的数学计算是在内存栈里操作的,Java会对i5、i6进行拆箱操作,其实比较的是基本类型(40=40+0),他们的值相同,因此结果为True。
当数值大于127时,就不会在使用Integer中的缓存池,而是会new 一个对象返回 所以 i7 == i8 结果为:”false“