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] == 5
在printf()
方法中,它打印5个罚款,但在println()
为什么它打印4应该是5它背后的原因是什么?
答案 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的原因