Java拆箱和装箱
学而不思则罔,思而不学则殆
定义
【装箱】把基本类型用它们相应的引用类型包装起来,使其具有对象的性质。int包装成Integer、float包装成Float;装箱是将值类型转换为引用类型
【拆箱】和装箱相反,将引用类型的对象简化成值类型的数据;拆箱是将引用类型转换为值类型
可拆装箱的类型
对应关系:
- byte 《==》Byte
- short 《==》Short
- int 《==》Integer
- long 《==》 Long
- char 《==》 Character
- double《==》Double
- float《==》Float
- boolean《==》Boolean
研究
为了测试拆箱和装箱,我定义一些打印结果的方法,如下:
byte b = 1;
Byte bb = 1;
char c = 65;
Character cc = 'A';
short s = 1;
Short ss = 1;
int i = 1;
Integer ii = 1;
long l = 1L;
Long ll = 1L;
float f = 1F;
Float ff = 1F;
double d = 1D;
Double dd = 1D;
private static void show(Object object) { System.out.println("" + object.getClass()); }
private static void show(byte object) { System.out.println("byte:" + object); }
private static void show(Byte object) { System.out.println("Byte:" + object); }
private static void show(char object) { System.out.println("char:" + object); }
private static void show(Character object) { System.out.println("Character:" + object); }
private static void show(short object) { System.out.println("short:" + object); }
private static void show(Short object) { System.out.println("Short:" + object); }
private static void show(int object) { System.out.println("int:" + object); }
private static void show(Integer object) { System.out.println("Integer:" + object); }
private static void show(long object) { System.out.println("long:" + object); }
private static void show(Long object) { System.out.println("Long:" + object); }
private static void show(float object) { System.out.println("float:" + object); }
private static void show(Float object) { System.out.println("Float:" + object); }
private static void show(double object) { System.out.println("double:" + object); }
private static void show(Double object) { System.out.println("Double:" + object); }
测试相同类型的运算
测试byte和Byte
让byte和Byte之间相互相加,看看最终的结果是什么,
show(b + bb); //int:2 当我只保留show(Object object)这个方法时:class java.lang.Integer
show(b + b); //int:2 class java.lang.Integer
show(bb + bb);//int:2 class java.lang.Integer
结论:byte和Byte运算,默认会是int类型(拆箱运算),当只有show(Object object)的方法时,自动装箱为Integer类型,而不是Byte类型
测试char和Character
让char和Character 之间相互相加,看看最终的结果是什么,
show(c + cc); //int:130 只保留show(Object object)方法: class java.lang.Integer
show(c + c); //int:130 class java.lang.Integer
show(cc + cc); //int:130 class java.lang.Integer
结论:char和Character,默认会是int类型(拆箱运算),当只有show(Object object)的方法时,自动装箱为Integer类型,而不是Character 类型
测试short 和Short
show(s + s); //int:2 只保留show(Object object)方法: class java.lang.Integer
show(s + ss); //int:2 class java.lang.Integer
show(ss + ss); //int:2 class java.lang.Integer
结论:short 和Short 运算,默认会是int类型(拆箱运算),当只有show(Object object)的方法时,自动装箱为Integer类型,而不是Short 类型
测试int 和Integer
show(i + i); //int:2 只保留show(Object object)方法: class java.lang.Integer
show(i + ii); //int:2 class java.lang.Integer
show(ii + ii); //int:2 class java.lang.Integer
结论:int 和Integer 运算,默认会是int类型(拆箱运算),当只有show(Object object)的方法时,自动装箱为Integer类型
测试long 和Long
show(l + l); //long:2 只保留show(Object object)方法: class java.lang.Long
show(l + ll); //long:2 class java.lang.Long
show(ll + ll); //long:2 class java.lang.Long
结论:long 和Long 运算,默认会是long 类型(拆箱运算),当只有show(Object object)的方法时,自动装箱为Long类型
测试float 和Float
show(f + f); //float:2.0 只保留show(Object object)方法: class java.lang.Float
show(f + ff); //float:2.0 class java.lang.Float
show(ff + ff); //float:2.0 class java.lang.Float
结论:float 和Float 运算,默认会是float 类型(拆箱运算),当只有show(Object object)的方法时,自动装箱为Float 类型
测试double 和Double
show(d + d); //double:2.0 只保留show(Object object)方法: class java.lang.Double
show(d + dd); //double:2.0 class java.lang.Double
show(dd + dd); //double:2.0 class java.lang.Double
结论:double 和Double 运算,默认会是double 类型(拆箱运算),当只有show(Object object)的方法时,自动装箱为Double 类型
整理结论:
- 值类型数据和引用型对象之间运算,会默认拆箱为值类型运算,结果也是值类型
- 其中byte,char,short运算时会转换为int,在运算,最终结果也是int
- long,float,double运算结果是其自身,
测试不同类型之间的运算
Byte
show(bb + bb); //int:2 class java.lang.Integer
show(bb + cc); //int:66 class java.lang.Integer
show(bb + ss); //int:2 class java.lang.Integer
show(bb + ii); //int:2 class java.lang.Integer
show(bb + ll); //long:2 class java.lang.Long
show(bb + ff); //float:2.0 class java.lang.Float
show(bb + dd); //double:2.0 class java.lang.Double
Character
show(cc + bb); //int:66 class java.lang.Integer
show(cc + cc); //int:130 class java.lang.Integer
show(cc + ss); //int:66 class java.lang.Integer
show(cc + ii); //int:66 class java.lang.Integer
show(cc + ll); //long:66 class java.lang.Long
show(cc + ff); //float:66.0 class java.lang.Float
show(cc + dd); //double:66.0 class java.lang.Double
Short
show(ss + bb); //int:2 class java.lang.Integer
show(ss + cc); //int:66 class java.lang.Integer
show(ss + ss); //int:2 class java.lang.Integer
show(ss + ii); //int:2 class java.lang.Integer
show(ss + ll); //long:2 class java.lang.Long
show(ss + ff); //float:2.0 class java.lang.Float
show(ss + dd); //double:2.0 class java.lang.Double
Integer
show(ii + bb); //int:2 class java.lang.Integer
show(ii + cc); //int:66 class java.lang.Integer
show(ii + ss); //int:2 class java.lang.Integer
show(ii + ii); //int:2 class java.lang.Integer
show(ii + ll); //long:2 class java.lang.Long
show(ii + ff); //float:2.0 class java.lang.Float
show(ii + dd); //double:2.0 class java.lang.Double
Long
show(ll + bb); //long:2 class java.lang.Long
show(ll + cc); //long:66 class java.lang.Long
show(ll + ss); //long:2 class java.lang.Long
show(ll + ii); //long:2 class java.lang.Long
show(ll + ll); //long:2 class java.lang.Long
show(ll + ff); //float:2.0 class java.lang.Float
show(ll + dd); //double:2.0 class java.lang.Double
Float
show(ff + bb); //float:2.0 class java.lang.Float
show(ff + cc); //float:66.0 class java.lang.Float
show(ff + ss); //float:2.0 class java.lang.Float
show(ff + ii); //float:2.0 class java.lang.Float
show(ff + ll); //float:2.0 class java.lang.Float
show(ff + ff); //float:2.0 class java.lang.Float
show(ff + dd); //double:2.0 class java.lang.Double
Double
show(dd + bb); //double:2.0 class java.lang.Double
show(dd + cc); //double:66.0 class java.lang.Double
show(dd + ss); //double:2.0 class java.lang.Double
show(dd + ii); //double:2.0 class java.lang.Double
show(dd + ll); //double:2.0 class java.lang.Double
show(dd + ff); //double:2.0 class java.lang.Double
show(dd + dd); //double:2.0 class java.lang.Double
结论如下表:
| 类型 | Byte | Character | Short | Integer | Long | Float | Double |
|---|---|---|---|---|---|---|---|
| Byte | int | int | int | int | long | flaot | double |
| Character | int | int | int | int | long | flaot | double |
| Short | int | int | int | int | long | flaot | double |
| Integer | int | int | int | int | long | flaot | double |
| Long | long | long | long | long | long | flaot | double |
| Float | flaot | flaot | flaot | flaot | flaot | flaot | double |
| Double | double | double | double | double | double | double | double |
研究==和equals
== 比较的值类型大小和引用对象的引用值(可以理解为指针)
equals比较的对象的值时候相等
Boolean b1 = new Boolean(false);
Boolean b2 = new Boolean(false);
System.out.println(System.identityHashCode(true)); //621009875
System.out.println(System.identityHashCode(true)); //621009875
System.out.println(System.identityHashCode(false)); //1265094477
System.out.println(System.identityHashCode(false)); //1265094477
System.out.println(System.identityHashCode(b1)); //2125039532
System.out.println(System.identityHashCode(b2)); //312714112
System.out.println(b1 == b2); //false
System.out.println(b1.equals(b2)); //true
System.out.println(b1 == false); //true
System.out.println(b2 == false); //true
这里打印的 System.out.println(System.identityHashCode(true))和System.out.println(System.identityHashCode(false))两个为啥两两相等?因为默认装箱,最终打印的Boolean中的默认的对象,相当于与是同一个对象,它的identityHashCode值当然相等了。
/**
* The {@code Boolean} object corresponding to the primitive
* value {@code true}.
*/
public static final Boolean TRUE = new Boolean(true);
/**
* The {@code Boolean} object corresponding to the primitive
* value {@code false}.
*/
public static final Boolean FALSE = new Boolean(false);
那为啥 System.out.println(System.identityHashCode(b1)); 和System.out.println(System.identityHashCode(b2)); //312714112 又不相等?
这两的b1和b2是不同的对象,虽然他们的值相等,但是在内存中并不是同一块区域,所以identityHashCode的值不相等
基本类型的缓存
ByteCache
[-128,127]
private static class ByteCache {
private ByteCache(){}
static final Byte cache[] = new Byte[-(-128) + 127 + 1];
static {
for(int i = 0; i < cache.length; i++)
cache[i] = new Byte((byte)(i - 128));
}
}
CharacterCache
[0,127]
private static class CharacterCache {
private CharacterCache(){}
static final Character cache[] = new Character[127 + 1];
static {
for (int i = 0; i < cache.length; i++)
cache[i] = new Character((char)i);
}
}
ShortCache
[-128,127]
private static class ShortCache {
private ShortCache(){}
static final Short cache[] = new Short[-(-128) + 127 + 1];
static {
for(int i = 0; i < cache.length; i++)
cache[i] = new Short((short)(i - 128));
}
}
IntegerCache
//range [-128, 127]
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}
LongCache
//[-128,127]
private static class LongCache {
private LongCache(){}
static final Long cache[] = new Long[-(-128) + 127 + 1];
static {
for(int i = 0; i < cache.length; i++)
cache[i] = new Long(i - 128);
}
}
Float和Double没有缓存
测试缓存
Integer i1 = 1;//装箱为引用类型
Integer i2 = 1;//装箱为引用类型
Integer i3 = new Integer(1);
Integer i4 = new Integer(1);
int i5 = i3;//拆箱为数值类型
int i6 = i4;//拆箱为数值类型
System.out.println(System.identityHashCode(i1)); //621009875
System.out.println(System.identityHashCode(i2)); //621009875 i1 和 i2 相等,装箱复用了Integer中的缓存对象
System.out.println(System.identityHashCode(i3)); //1265094477
System.out.println(System.identityHashCode(i4)); //2125039532 i3 和 i4不相等,生成了新对象
System.out.println(System.identityHashCode(i5)); //621009875
System.out.println(System.identityHashCode(i6)); //621009875 i1 和 i2 相等,装箱复用了Integer中的缓存对象
System.out.println(System.identityHashCode(127)); //312714112
System.out.println(System.identityHashCode(127)); //312714112 相等,装箱复用了Integer中的缓存对象
System.out.println(System.identityHashCode(128)); //692404036
System.out.println(System.identityHashCode(128)); //1554874502 装箱,但是不在缓存对象范围内,所以不相等
System.out.println(System.identityHashCode(-128)); //1846274136
System.out.println(System.identityHashCode(-128)); //1846274136 相等,装箱复用了Integer中的缓存对象
System.out.println(System.identityHashCode(-129)); //1639705018
System.out.println(System.identityHashCode(-129)); //1627674070 装箱,但是不在缓存对象范围内,所以不相等
System.out.println(i1 == i2); //true 同一对象,应用地址相等
System.out.println(i1.equals(i2));//true 相等
System.out.println(i1 == i3);//false 不同对象,false
System.out.println(i1.equals(i3));//true 比较数值相等
System.out.println(i5 == i6);//true 数值类型,比较数值大小
Java拆箱装箱深入解析
1万+

被折叠的 条评论
为什么被折叠?



