深入解析Integer类型:
补全Swap方法,使a b两值交换。
public static void main(String[] args) {
// TODO Auto-generated method stub
Integer a=2;
Integer b=2;
swap(a,b);
System.out.println("a value is " +a);
System.out.println("b value is " +b);
}
private static void swap(Integer num1,Integer num2){
}
方法1(错误):
private static void swap(Integer num1,Integer num2){
Integer temp=num1;
num2=num1;
num1=temp;
}
由于Java传输数据采用值传递跟引用传递。
基本数据类型采用值传递,
Integer是包装类,属于基本数据类型int的封装类型,其传值采用值传递。
JDK1.5以后装箱拆箱是其一个特性。
本来应该是 int a=1, 现在Integer a=1 可以直接赋值是因为执行了装箱操作:Integer.valueOf:[1]
调用swap的时候,只是传给其a与b的副本,修改副本的value不影响a与b的值。
/**Integer与int的区别
区别1:创建Integer需要进行实例化。而int不需要实例化。因为Integer是一个对象。
区别2:Integer默认是null。而int默认是0.
区别3:判断Intege用equals,而判断int用==。 原因的话挖坑,文章后期埋。
**/
方法2:
探索Integer怎么赋值:
查看字节码文件。
1. 进入JDK目录。
2. Javap.exe -c +要解析的class路径。
3. class字节码文件解析--挖坑,以后再埋。
4. 调用Integer.valueOf把 1 压入站点。
查看源码文件:
Integer类中里重要的是变量value。该值是final类型。
如果能够使用set方式修改,那可以满足要求。
使用set方式可以使用反射机制,用反射获取到这个值。
private static void swap(Integer num1,Integer num2){
try {
Field field=Integer.class.getDeclaredField("value");
int temp=num1;
field.set(num1, num2);
field.set(num2, num1);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
但是这样由于value是final修饰,会抛出异常。
在反射机制中,有访问权限的设置。需要设置override值。
增加setAccessible并执行
private static void swap(Integer num1,Integer num2){
try {
Field field=Integer.class.getDeclaredField("value");
int temp=num1; //拆箱操作
field.setAccessible(true);
field.set(num1, num2);
field.set(num2, num1);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
结果是:
a value is 2
b value is 2
这是由于valueOf引起的。接下来查看valueOf的源码:
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
当i在IntegerCache的一定范围内(low是-128,high是127),值从cache里取。取值方法是i+ -(-128).
当i是1的时候,取的值应该是cache数组的129。
在做field.set(num1,num2)时候,其实就等于:cache[1+128]=2
在做field.set(num2,temp)时候,temp是int类型的1,而field.set参数是object对象,所以会进行一次自动的装箱操作。等同于:
field.set(num2, Integer.valueOf(num1));
然后去cache中获取值,得到的是cache[11+28]:2.
所以最终结果是a=2,b=2。
解决方案:
先埋文章开头的坑:
当a>128的时候,用==就会出现问题,所以一般判断Integer相等,用equals来进行判断。
==比较的是内存地址是否一致。
当Integer在-128到127的时候,数据是从IntegerCache.cache[]中取。相当于是从一个对象中取,所以地址一致。
而当Integer取128的时候,重新分配了一个对象,地址发生变化,所以用==判断为false.
解决方案之解决方案:
主动刺破 temp的自动装箱,让其不从cache数组中取值。而从object对象中取。
private static void swap(Integer num1,Integer num2){
try {
Field field=Integer.class.getDeclaredField("value");
int temp=num1;
field.setAccessible(true);
field.set(num1, num2);
field.set(num2, new Integer(temp));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
当然,这样会破坏Integer的封装性。在实际项目中不建议这样使用。