2013-05-09 36 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