2013-05-09 38 views
9

我只是探索Java反射API和我遇到下面的代码片断Java反射片段输出

public class Main { 
    public static void main(String[] args) throws IllegalAccessException, NoSuchFieldException{ 
      Field value=Integer.class.getDeclaredField("value"); 
      value.setAccessible(true); 
      value.set(42, 43); 

      System.out.printf("six times seven %d%n",6*7); 
      System.out.printf("six times seven %d%n",42); 
      System.out.println(42); 
     } 
    } 

输出:

six times seven 43 
six times seven 43 
42 

我读其中规定所述一组方法的文档,它设置值对于给定对象的字段。但我无法理解代码的输出,因为它应该在所有情况下打印42。

任何人都可以请深入了解代码中发生了什么吗?

+1

http://www.dzone.com/snippets/reflection-integer-destroyer – 2013-05-09 17:01:43

回答

4
 System.out.println(42); 

正在调用println(int)而不是println(Object)。拳击从未发生。这使得它更快,并且在1.5之前工作。

在其他情况下,您正在通过Integer.valueOf(int)进行装箱。此方法被定义为始终返回完全相同的Integer对象,其值介于-128和127之间(对其他值可能有相同或不同的行为)。因此,无论程序中装入了哪个42,您都会得到相同的对象,并且在此对象中设置值value时,无论通过哪个引用,它都会更改。

如果你把在拳击明确到代码,它应该是这样的:

 value.set(Integer.valueOf(42), 43); 

     System.out.printf("six times seven %d%n",Integer.valueOf(6*7)); 
     System.out.printf("six times seven %d%n",Integer.valueOf(42)); 
     System.out.println(42); 

我们知道Integer.valueOf(恰好返回42相同的对象,代码是有效的:

 Integer obj42 = Integer.valueOf(42); 

     value.set(Integer.valueOf(obj42, 43); 

     System.out.printf("six times seven %d%n", obj42); 
     System.out.printf("six times seven %d%n", obj42); 
     System.out.println(42); 
+0

这很难理解。你能给我一些参考,我可以在哪里找到更多的细节? – ankurtr 2013-05-09 17:11:30

+0

@ ankur.trapasiya拳击?详细信息在'Integer.valueOf'的API文档中和JLS中。 – 2013-05-09 17:13:22

+0

@ ankur.trapasiya [[这里](http://stackoverflow.com/questions/3130311/weird-java-boxing)]你有关于拳击和缓存整数有趣的问题。此外,由于'printf(String format,Object ... args)'需要Object作为'format'中使用的参数,因此Java会自动将int整型为Integer,但由于您将缓存的Integer的值更改为42,这个值将被打印。 'println(int)'不会有这个问题,因为它不需要装箱。你也可以尝试'System.out.printf(“六次7%d%n”,新的Integer(6 * 7));'创建一个不会被缓存的值为42的新整数 – Pshemo 2013-05-09 17:16:35