2016-01-15 45 views
14

我有這樣的代碼(現在拋開其是否適合):不同的行爲運行和調試程序的Java,Eclipse的

Class<?> cacheClass = Class.forName("java.lang.Integer$IntegerCache"); 
    Field cacheField = cacheClass.getDeclaredField("cache"); 
    cacheField.setAccessible(true); 
    Field modifiersField = Field.class.getDeclaredField("modifiers"); 
    modifiersField.setAccessible(true); 
    modifiersField.setInt(cacheField, cacheField.getModifiers() & ~Modifier.FINAL); 

    Integer betterCache[] = new Integer[255]; 
    for (int i = 0; i < betterCache.length; i++) { 
     betterCache[i] = 20; 
    } 
    cacheField.set(null, betterCache); 
    System.out.println(10); 
    System.out.println((Integer) 10); 

我預計第二println打印20,因爲我換成緩存Integers 20。當我在Eclipse中調試程序時,它會像我期望的那樣執行程序,它會從緩存中獲取值並打印20,而當我從IDE或通過調用java運行時,它會在兩種情況下打印10。這種行爲如何解釋?

UPD: 如果使用1.8 javac編譯,它的工作方式就是這樣。如果使用1.6版進行編譯,它將打印10和20。

+0

您正在兩種情況下都打印10張。那麼爲什麼要打印20呢? –

+0

在第二種情況下,它是一個對象,因此它調用'Integer.valueOf'方法來打印它,並且在該方法中,它從緩存中取值,我用一個填充了20的數組代替。 – cliffroot

+2

有趣的問題(儘管您在播放與火)。 – mks

回答

2

編輯

我是完全錯誤

肯定你在玩火,以我的觀點來看,這是一個競爭條件(在Java 8不安全線程)。如果您選中此項:

Class<?> cacheClass = Class.forName("java.lang.Integer$IntegerCache"); 
    Field cacheField = cacheClass.getDeclaredField("cache"); 
    cacheField.setAccessible(true); 
    Field modifiersField = Field.class.getDeclaredField("modifiers"); 
    modifiersField.setAccessible(true); 
    modifiersField.setInt(cacheField, cacheField.getModifiers() & ~Modifier.FINAL); 
    Integer firstCache[] = (Integer[])cacheField.get(null); 
    Integer betterCache[] = new Integer[255]; 
    for (int i = 0; i < betterCache.length; i++) { 
     betterCache[i] = 20; 
    } 
    System.out.println(firstCache == betterCache); 
    cacheField.set(null, betterCache); 
    System.out.println(10); 
    for (int i = 0; i < 1000000; i++) { 
     System.out.println((Integer) 10);  
    } 

您會看到Java刻錄。

+0

感謝您的回答。我仍然不明白爲什麼改變'20'(基本上調用'valueOf')來創建新的值會改變這種行爲。它似乎並沒有在編譯時進行評估(儘管字節碼的東西對我來說很不清楚),因爲在兩個版本的字節碼中,第二個'println'有相同的語句'bipush 10'。請參閱更新我的問題 – cliffroot

+1

@cliffroot我不知道,但是我可以看到有/沒有斷點的差異在調試模式下。我開始在競賽條件下思考。 –

+1

@cliffroot我編輯! –

4

這絕對是由於即時編譯器造成的。您應該添加-XX:+ PrintCompilation到JVM選項,它也更明顯,如果你重複

System.out.println((Integer) 10); 

了很多次。 你會發現,編譯

java.lang.Integer::valueOf (32 bytes) 

java.nio.ByteBuffer::arrayOffset (35 bytes) 

影響的結果。

+0

您是否介意解釋'-xx:+ PrintCompilation'的輸出......我經歷了它,但真的無法理解...... – Codebender

相關問題