深度解析Integer

深入解析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的封装性。在实际项目中不建议这样使用。









评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值