首先,八种数据类型分别是;int、short、float、double、long、boolean、byte、char
它们的封装类分别是:Integer、Short、Float、Double、Long、Boolean、Byte、Character
关于自动装箱与拆箱:
如:Integer ser = 10;
以上的声明就是用到了自动的装箱:解析为 Integer ser= new Integer(10);因为10是属于基本数据类型的,原则上它是不能直接赋值给一个对象Integer的,但当javac发现在一个需要Integer的上下文里出现了int类型的值,就会通过Integer.valueOf()自动把这个值装箱为Integer,自动将基本数据类型转化为对应的封装类型。成为一个对象以后就可以调用对象所声明的所有的方法
关于自动拆箱:故名思议就是将对象重新转化为基本数据类型:
装箱
Integer ser = 10;
拆箱
int ser1 = ser;自动拆箱有个很典型的用法就是在进行运算的时候:因为对象时不恩直接进行运算的,而是要转化为基本数据类型后才能进行加减乘除
Integer ser= 10; 进行计算时隐含的有自动拆箱
System.out.print(ser–);
在-128~127 之外的数
Integer num1 = 297; Integer num2 = 297;
System.out.println("num1==num2: "+(num1==num2));
在-128~127 之内的数
Integer num3 = 97; Integer num4 = 97;
System.out.println("num3==num4: "+(num3==num4));
运行结果如下:
这是因为JVM会自动维护八种基本类型的常量池,int常量池中初始化-128~127的范围,所以当为Integer i=127时,在自动装箱过程中是取自常量池中的数值,而当Integer i>128时,i不在常量池范围内,所以在自动装箱过程中需new i,所以地址不一样。
“==”比较的是地址,而num1和num2两个对象的地址不同,即是两个对象,所以是false.
为了加大对简单数字的重利用,java定义:在自动装箱时对于值从–128到127之间的值,它们被装箱为Integer对象后,会存在内存中被重用,始终只存在一个对象 ;而如果超过了从–128到127之间的值,被装箱后的Integer对象并不会被重用,即相当于每次装箱时都新建一个 Integer对象;
以上的现象是由于使用了自动装箱所引起的,对于一般类来说,用new来进行实例化,就会每次new就都一个新的对象;
以下时实现自动装箱过程所调用的方法:
//boolean原生类型自动装箱成Boolean
public static Boolean valueOf(boolean b) {
return (b ? TRUE : FALSE);
}
//byte原生类型自动装箱成Byte
public static Byte valueOf(byte b) {
final int offset = 128;
return ByteCache.cache[(int)b + offset];
}
//byte原生类型自动装箱成Byte
public static Short valueOf(short s) {
final int offset = 128;
int sAsInt = s;
if (sAsInt >= -128 && sAsInt <= 127) { // must cache
return ShortCache.cache[sAsInt + offset];
}
return new Short(s);
}
//char原生类型自动装箱成Character
public static Character valueOf(char c) {
if (c <= 127) { // must cache
return CharacterCache.cache[(int)c];
}
return new Character(c);
}
//int原生类型自动装箱成Integer
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
//int原生类型自动装箱成Long
public static Long valueOf(long l) {
final int offset = 128;
if (l >= -128 && l <= 127) { // will cache
return LongCache.cache[(int)l + offset];
}
return new Long(l);
}
//double原生类型自动装箱成Double
public static Double valueOf(double d) {
return new Double(d);
}
//float原生类型自动装箱成Float
public static Float valueOf(float f) {
return new Float(f);
}
通过分析源码发现,只有double和float的自动装箱代码没有使用缓存,每次都是new 新的对象,其它的6种基本类型都使用了缓存策略。使用缓存策略是因为,缓存的这些对象都是经常使用到的(如字符、-128至127之间的数字),防止每次自动装箱都创建一此对象的实例。而double、float是浮点型的,没有经常使用到的数据,缓存效果没有其它几种类型使用效率高。且装箱调用的都是valueOf方法。
而拆箱跟自动装箱的方向相反,将Integer及Double这样的引用类型的对象重新简化为基本类型的数据。
如下:
int i = new Integer(2);//这是拆箱
编译器内部会调用intintValue()返回该Integer对象的int值。
总结就是:自动装箱和拆箱是由编译器来完成的,编译器会在编译期根据语法决定是否进行装箱和拆箱动作,装箱过程是通过调用包装器的valueOf方法实现的,而拆箱过程是通过调用包装器的xxxvalue方法实现的(xxx代表对应的基本数据类型)。