这里输出不同的原因是什么?

时间:2016-03-26 17:37:54

标签: java

int a = 2;
int b = a + a;

Class cache = Integer.class.getDeclaredClasses()[0]; 
Field myCache = cache.getDeclaredField("cache"); 
myCache.setAccessible(true);

Integer[] newCache = (Integer[]) myCache.get(cache); 
newCache[132] =  newCache[133];

System.out.printf("%d",b); // 5
System.out.println(b); // 4

此处我将cache[132]的值更改为cache[133],这意味着现在cache[132] == 5printf()方法中,它打印5个罚款,但在println()为什么它打印4应该是5它背后的原因是什么?

3 个答案:

答案 0 :(得分:6)

println有一个接受int的重载。因此在行

System.out.println(b);

int永远不会使用Object转换为Integer.valueOf

printf有签名

public PrintStream printf(String format, Object ... args)

因此4会自动退回到Integer对象5(使用已修改的缓存),因此会打印5

答案 1 :(得分:1)

在javap -verbose package.YourClassName

之后
    51: getstatic     #67                 // Field java/lang/System.out:Ljava/io/PrintStream;
    54: ldc           #73                 // String %d
    56: iconst_1
    57: anewarray     #3                  // class java/lang/Object
    60: dup
    61: iconst_0
    62: iload_2
    63: invokestatic  #75                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
    66: aastore
    67: invokevirtual #79                 // Method java/io/PrintStream.printf:(Ljava/lang/String;[Ljava/lang/Object;)Ljava/io/PrintStream;
    70: pop
    71: getstatic     #67                 // Field java/lang/System.out:Ljava/io/PrintStream;
    74: iload_2
    75: invokevirtual #85                 // Method java/io/PrintStream.println:(I)V
    78: return

您会看到在指令63处调用Integer.valueOf,因此使用Integer缓存。在第75点,println签名不是一个对象,而是一个直接的原始int,因此不涉及整数缓存。

答案 2 :(得分:1)

如果您尝试以下代码

System.out.println(Integer.valueOf(b)); 

你会注意到5为此打印。现在,对于printf方法,您可以使用以下代码。

System.out.printf("%d",b); 

如果您看到printf接受String作为第一个参数而Object接受第二个参数。你有b作为原始类型(int)。自动装箱发生,并使用Integer.java class method : valueOf(int i)

此外,如果您声明整数,那么在两种情况下都会看到4被打印,因为没有自动装箱。通常-128到127被缓存,您已修改内部缓存。 valueOf使用缓存,这就是您看到不同oputput的原因