运行和调试Java、Eclipse程序的不同行为

2022-09-03 15:47:19

我有这个代码(暂时搁置它的适当性):

    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);

我希望第二个打印20,因为我用20替换了缓存。当我在Eclipse中调试程序时,它会像我预期的那样,从缓存中获取值并打印20,而在两种情况下,当我只是从IDE或调用运行它时,它都会打印10。如何解释这种行为?printlnIntegersjava

UPD:如果使用1.8 javac编译,它的工作方式是这样的。如果使用1.6版本编译,它将打印10和20。


答案 1

这绝对是由Just in Time Compiler引起的。您应该将-XX:+PrintCompilation添加到JVM选项中,如果您迭代,它也更明显

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

很多时候。您会注意到编译

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

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

影响结果。


答案 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的燃烧。