无论在Android还是java中,我们都会遇到基本数据类型以及对应到引用数据类型的转换操作等等,这里通过装箱拆箱操作以及类型转换进行实例分析。
装箱和拆箱是jdk 1.5以及上版本出现的,其中
装箱是指在程序设计中,值类型实例到对象的转换,它暗示在运行时实例将携带完整的类型信息,并在堆中分配。
拆箱是将引用类型转换为值类型,利用装箱和拆箱功能,可通过允许值类型的任何值与Object 类型的值相互转换,将值类型与引用类型链接起来。
通过解释释义,我们可以理解
Integer a = 1;
这就是一个装箱操作,会自动创建一个Integer对象,a指向这个对象。
int a = new Integer(1);
与装箱操作相反,创建一个值为1的Integer对象,同时将Integer类型转换为int基本类型,
我们可以可以这样理解:将“箱”视为一个容器,其中1为一个值,将数值1加入这个容器,形成的对象就是装箱,将这个容器去掉,拿出这个1的操作就叫做拆箱,
对于Integer\int来说,装箱的过程就是调用对应类型的valueOf方法,拆箱的过程就是调用对应类的intValue()方法.以下类型具有装箱拆箱操作:
例如Integer中valueOf函数
public static Integer valueOf(int i) {
return i >= 128 || i < -128 ? new Integer(i) : SMALL_VALUES[i + 128];
}
/**
* A cache of instances used by {@link Integer#valueOf(int)} and auto-boxing
*/
private static final Integer[] SMALL_VALUES = new Integer[256];
static {
for (int i = -128; i < 128; i++) {
SMALL_VALUES[i + 128] = new Integer(i);
}
}
intValue函数
@Override
public int intValue() {
return value;
}
我们可以根据上面提及的操作可以了解到通过赋值的方式触发装箱和拆箱操作,但是其他方式如何触发么?我们根据当前一些常见的java基础问题一一分析。
int mint127 = new Integer(127);//拆箱操作
int mint1 = 1;
Integer mInteger127a = 127; //装箱操作
Integer mInteger127b = 127;//装箱操作
int mint128 = 128;
Integer mNewInteger127a = new Integer(127);
Integer mNewInteger128b = new Integer(128);
Integer mInteger128a = 128;//装箱操作
Integer mInteger128b = 128;//装箱操作
Long mLong127 = 127L;//装箱操作
Long mLong128 = 128L;//装箱操作
Short mShort127 = 127;
short mshort1 = 1;
byte mbyte1 = 1;
byte mByte1 = new Byte((byte)1);;
Byte mByte127 = new Byte((byte)127);
Byte mResult= (byte) (mByte1+mByte127);//先拆箱相加,由于+操作会将变量转成int,只能强制转为byte,导致超范围,数据损失
System.out.println("mint127 == mInteger127a -->"+(mint127 == mInteger127a));
System.out.println("mInteger127a== mInteger127b -->"+(mInteger127a== mInteger127b));
System.out.println("mInteger128a== mInteger128b -->"+(mInteger128a== mInteger128b));
System.out.println("(mInteger127a+mint1)== mNewInteger128b -->"+((mInteger127a+mint1)== mNewInteger128b));
System.out.println("(mLong127+mint1)== mNewInteger128b -->"+((mLong127+mint1)== mNewInteger128b))
;
System.out.println("(mLong128.equals(mLong127+mint1)) -->"+(mLong128.equals(mLong127+mint1)));
System.out.println("(mLong128==(mLong127+mint1)) -->"+(mLong128==(mLong127+mint1)));
System.out.println("(mNewInteger128b.equals(mLong127+mint1)) -->"+(mNewInteger128b.equals(mLong127+mint1)));
System.out.println("(mNewInteger128b==(mLong127+mint1)) -->"+(mNewInteger128b==(mLong127+mint1)));
System.out.println("(mNewInteger128b.equals(mShort127+mint1)) -->"+(mNewInteger128b.equals(mShort127+mint1)));
System.out.println("(mNewInteger128b==(mShort127+mint1)) -->"+(mNewInteger128b==(mShort127+mint1)));
System.out.println("(mNewInteger128b==(mShort127+mshort1)) -->"+(mNewInteger128b==(mShort127+mshort1)));
System.out.println("(mNewInteger128b==(mByte127+mbyte1)) -->"+(mNewInteger128b==(mByte127+mByte1)));
System.out.println("(byte) (mByte1+mByte127) -->"+mResult);
以下是运行结果:
mint127 == mInteger127a -->true //mInteger127a使用intValue() 拆箱操作
mInteger127a== mInteger127b -->true //地址相同,在-128到127范围内
mInteger128a== mInteger128b -->false //地址不同,通过valueOf()函数new的两个对象
(mInteger127a+mint1)== mNewInteger128b -->true //可以理解只要有int等基本类型,在加减或者比较操作中都需要拆箱然后处理,例如mint1
(mLong127+mint1)== mNewInteger128b -->true //拆箱比较
(mLong128.equals(mLong127+mint1)) -->true //拆箱,比值
(mLong128==(mLong127+mint1)) -->true //拆箱,比值。问题1,见下解释
(mNewInteger128b.equals(mLong127+mint1)) -->false //问题2,因为mLong127拆箱成long,总体转化为long型,equals比较返回false,见下解释
(mNewInteger128b==(mLong127+mint1)) -->true //拆箱比值
(mNewInteger128b.equals(mShort127+mint1)) -->true //问题3,拆箱,比值,见下解释
(mNewInteger128b==(mShort127+mint1)) -->true //拆箱,比值
(mNewInteger128b==(mShort127+mshort1)) -->true //拆箱,比值
(mNewInteger128b==(mByte127+mbyte1)) -->true //拆箱,比值
(byte) (mByte1+mByte127) -->-128 //因为mByte1拆箱为1,mByte127为127,这时候相加,自动转换为int型,结果128,超出byte范围,强制转为byte经过计算补码1000 0000为-128
上面这么多问题,我们一个个解释,首先看一个基础知识,类型转换
隐式类型转换:
要实现隐式类型转换,需要满足两个条件,第一两种类型彼此兼容,第二目标类型取
值范围必须大于源类型。所有的数字类型,包括整形和浮点型彼此都可以进行转换。
转换方向为:
注意:二元运算符(包括比较运算符)来说,如果一个操作数的类型是float、double或long,则另一个操作数被转换为float、double或long,否则两个操作数都被转换为int型(即为byte、short、char 会自动提升至int)。
问题1即可说明(mLong128==(mLong127+mint1)) -->true,双方都转为了long型比较。所以true,
那么问题2(mNewInteger128b.equals(mLong127+mint1)) -->false与问题(mNewInteger128b.equals(mShort127+mint1)) -->true 结果为啥不同呢,问题2中mLong127+mint1最后为long型,问题3中mShort127+mint1为int型,我们可以看下equals这个函数,
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
我们可以发现,只有Integer类型才行,我们知道jdk1.5及以上版本,int可以通过装箱转为Integer对象,那么如果不是int类型,则不可,这也解释了问题2为啥结果为false,mLong127+mint1最后为long型,不能通过instanceof 判断为Integer类型。
我们可以通过以下testObject函数观察传入的到底是什么类型
public static String testObject(Object obj) {
if (obj instanceof Integer) {
return "Integer";
}else if (obj instanceof Long){
return "Long";
}else if (obj instanceof Short){
return "Short";
}else if (obj instanceof Float){
return "Float";
}else if (obj instanceof Double){
return "Double";
}else if (obj instanceof Boolean){
return "Boolean";
}else if (obj instanceof Byte){
return "Byte";
}else if (obj instanceof Character){
return "Character";
}
return "wrong type";
}
例如
System.out.println("(byte)1+(char)1-->"+testObject((byte)1+(char)1));
System.out.println("(int)1+(char)1-->"+testObject((int)1+(char)1));
System.out.println("(int)1+(float)1-->"+testObject((int)1+(float)1));
System.out.println("(long)1+(float)1-->"+testObject((long)1+(float)1));
结果如下
(byte)1+(char)1-->Integer
(int)1+(char)1-->Integer
(int)1+(float)1-->Float
(long)1+(float)1-->Float
强制类型转换: (表达式) 其功能是把表达式的运算结果强制转换成类型说明符所表示的类型。
同时需要注意在进行基本类型的强制类型转换的时候,从大范围往小范围转换,会有精度损失,甚至数据错误的可能。还需要注意+=等赋值运算符。
例如:对于short a = 1; a= a+ 1; 由于a+1运算时会自动提升表达式的类型,所以结果是int型,再赋值给short类型a时,编译器将报告需要强制转换类型的错误。
对于short a= 1; a += 1;由于 += 是java语言规定的运算符,java编译器会对它进行特殊处理,因此可以正确编译。