java integer源码_jdk之java.lang.Integer源码理解

基本数据类型的包装类java.lang.Integer是我们频繁使用的一个系统类,那么通过一个示例反应出的几个问题来深入理解一下此类的源码。

需求:实现Integer类型的两个数值交换。

1 packagecn.integer;2

3 public classDemo {4 public static voidmain(String[] args) {5 Integer a = 1;6 Integer b = 2;7 System.out.println("bofore swap a:"+a+",b:"+b);8 //交换a和b的值

9 swap(a,b);10 System.out.println("after swap a:"+a+",b:"+b);11 }12 /**

13 * 数据交换14 *@parama15 *@paramb16 */

17 private static voidswap(Integer a, Integer b) {18 /**

19 * 如何实现呢?尝试几种方法20 */

21 /*01.方式一(无法实现)22 a = a^b;23 b = a^b;24 a = a^b;*/

25

26 /*02.方式二(无法实现)27 int tmp = a;28 a = b;29 b = tmp;*/

30

31 /**

32 * 以上两种方式是因为java的值传递特性故无法实现数据交换。33 */

34 }35 }

Java值传递的示意图如下:

c8130ea8b4a43604ecada4f9b9980d0d.png

当调用swap(..)方法时,在堆中会创建这两个值得副本,形参num1和num2指向副本的数据。原ab指向的数据不会改变。

那么如何通过修改swap()方法实现呢?

观察java.lang.Integer源码:

public final class Integer extends Number implements Comparable{

...

}

可以发现 Integer和String一样,是final修饰的,这是因为jdk将这些系统类封装起来不希望被破坏。

继续看Integer类:

/*** The value of the {@codeInteger}.

*

*@serial

*/

private final intvalue;/*** Constructs a newly allocated {@codeInteger} object that

* represents the specified {@codeint} value.

*

*@paramvalue the value to be represented by the

* {@codeInteger} object.*/

public Integer(intvalue) {this.value =value;

}

这里的value也是使用final修饰的,那么如果想修改它的值,可以使用反射的方式获取value字段并进行修改。

修改swap()方法中代码:

1 public classDemo {2 public static voidmain(String[] args) {3 Integer a = 1;4 Integer b = 2;5 System.out.println("bofore swap a:"+a+",b:"+b);6 //交换a和b的值

7 swap(a,b);8 System.out.println("after swap a:"+a+",b:"+b);9 }10 /**

11 * 数据交换12 *@parama13 *@paramb14 */

15 private static voidswap(Integer a, Integer b) {16 try{17 //获取Integer类中私有字段value

18 Field field = Integer.class.getDeclaredField("value");19 /**

20 * 开启访问权限21 * public final class Field extends AccessibleObject implements Member {}22 * 跟进AccessibleObject23 * public void setAccessible(boolean flag) throws SecurityException {24 SecurityManager sm = System.getSecurityManager();25 if (sm != null) sm.checkPermission(ACCESS_PERMISSION);26 setAccessible0(this, flag);27 }28

29 private static void setAccessible0(AccessibleObject obj, boolean flag)30 throws SecurityException31 {32 if (obj instanceof Constructor && flag == true) {33 Constructor> c = (Constructor>)obj;34 if (c.getDeclaringClass() == Class.class) {35 throw new SecurityException("Cannot make a java.lang.Class" +36 " constructor accessible");37 }38 }39 obj.override = flag;40 }41 */

42 field.setAccessible(true);43 //临时变量

44 int tmp =a.intValue();45 //数据交换

46 field.set(a, b);47 field.set(b, tmp);48 } catch(Exception e) {49 e.printStackTrace();50 }51 }52 }

运行结果:

87972d0029f611372c213dd22001555c.png

诶,我去。怎么只改变了一个值?咋成功了一半呢?

01.首先,Integer a = 1; 这里会自动装箱,将 int类型的1 转换成 Integer类型。

通过valueOf方法进行装箱

1 public static Integer valueOf(inti) {2 if (i >= IntegerCache.low && i <=IntegerCache.high)3 return IntegerCache.cache[i + (-IntegerCache.low)];4 return newInteger(i);5 }

这个方法非常重要,如果传入的参数在 -128-127之间,会返回一个缓存中的数据。否则就 new出一个Integer对象!

Integer.IntegerCache是Integer中的内部类:

1 private static classIntegerCache {2 static final int low = -128;3 static final inthigh;4 static finalInteger cache[];5

6 static{7 //high value may be configured by property

8 int h = 127;9 String integerCacheHighPropValue =

10 sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");11 if (integerCacheHighPropValue != null) {12 try{13 int i =parseInt(integerCacheHighPropValue);14 i = Math.max(i, 127);15 //Maximum array size is Integer.MAX_VALUE

16 h = Math.min(i, Integer.MAX_VALUE - (-low) -1);17 } catch( NumberFormatException nfe) {18 //If the property cannot be parsed into an int, ignore it.

19 }20 }21 high =h;22

23 cache = new Integer[(high - low) + 1];24 int j =low;25 for(int k = 0; k < cache.length; k++)26 cache[k] = new Integer(j++);27

28 //range [-128, 127] must be interned (JLS7 5.1.7)

29 assert IntegerCache.high >= 127;30 }31

32 privateIntegerCache() {}33 }

02.当我们获取数值1时,

return IntegerCache.cache[i + (-IntegerCache.low)]

计算出IntegerCache.cache[129]的值(也就是1)返回。

cache这个数组存放着 -128-127这些数据。故index=129就是返回1。

03. 执行这行时 field.set(a, b);将传入的2复制给a,此时a为2.

注意:这里通过set方法改变的的是缓存cache数组中的数据!04. 当执行到 field.set(b, tmp);

tmp为1,而set方法的参数类型是Object,可以传入int类型的tmp

public voidset(Object obj, Object value)throwsIllegalArgumentException, IllegalAccessException

{if (!override) {if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {

Class> caller =Reflection.getCallerClass();

checkAccess(caller, clazz, obj, modifiers);

}

}

getFieldAccessor(obj).set(obj, value);

}

所以这个tmp=1是从Integer的缓存数组中取得,因上一行操作已经将cache中index为129位置得原数值1改变为了2,故在cache中获取的是2! 那么把2赋值给了b自然是2!(b对应的下标[130],a对应的下标[129])

我们发现,问题的关键在于这个缓存cache!

如果说可以避开走缓存这一步,我们就能实现数据交换。除了传入 -128-127之外的数据,我们还可以:

001.将tmp转换成Integer对象后在传入Field的set方法:

private static voidswap(Integer a, Integer b) {try{//获取Integer类中私有字段value

Field field = Integer.class.getDeclaredField("value");

field.setAccessible(true);//临时变量

int tmp =a.intValue();//数据交换

field.set(a, b);

field.set(b,newInteger(tmp));

}catch(Exception e) {

e.printStackTrace();

}

}

运行结果:

b697b42920cb4d6fecde7ef147587d73.png

002. 使用 Field类的 setInt方法

public void setInt(Object obj, inti)throwsIllegalArgumentException, IllegalAccessException

{if (!override) {if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {

Class> caller =Reflection.getCallerClass();

checkAccess(caller, clazz, obj, modifiers);

}

}

getFieldAccessor(obj).setInt(obj, i);

}

修改代码 field.setInt(b,tmp); 也可以实现。

003. 非要实现打印效果的话,使用非常规手短,直接在swap中打印结果...

private static voidswap(Integer a, Integer b) {

System.out.println("after swap a:2,b:1");

System.exit(0);

}

这个示例中涉及到技能点:

192b76e077faa86866ed72120030b5bd.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值