2016-03-26 25 views
9
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 

Şimdi cache[132] == 5 o yazdırır neden 4 o nedeni üzerinde arkasında ne 5 olmalıdır bunun 5 cezası yazdırır printf() yönteminde ama println() anlama cache[133] için cache[132] değeri değiştirmek?Farklı çıktıların sebebi nedir? İşte

+5

Kütüphane sınıfının belgelenmemiş iç yapısıyla uğraşmak zorunda kalıyorsunuz - neden makul davranışlar beklersiniz? –

+4

Gerçekten iyi bir neden olmadığı anlaşılan, burada yansımayı kullanıyorsunuz. Bunu neden yapmak istediğinizi veya neyi başarmaya çalıştığınız belli değil. Dahası, yansıma kullandığınızda, nesne durumunun ve değişmezlik garantilerinin birçoğu hızla boşa kalır ve bu yüzden dikkatli davranın. – Makoto

+0

eğer bunun nedenini iyi bilmiyorsanız, ancak "fiddling" diyemezsiniz @Oliver Charlesworth –

cevap

6

println, int kabul eden bir aşırı yüklemeye sahiptir. Bu nedenle hat

System.out.println(b); 

int yılında Integer.valueOf kullanarak Object dönüştürülür asla.

printf İmza çok 4Integer nesne 5 (değiştirilmiş önbellek kullanarak) autoboxed edilir

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

sahiptir ve bu nedenle 5 basılır.

+1

Bu tutar. Bu yüzden hata ayıklayıcıda göremedim; autobox, 'printf 'çağrıldığında zaten etkili olmuştu. – Makoto

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 

sonra Sen talimatı 63 at Integer.valueOf böylece Tamsayı önbelleği kullanarak, çağrılan görüyoruz. 75 noktada, println imzası bir nesneyi değil, daha doğrusu düz bir ilkel int, yani Tamsayı önbelleği içermez.

1

kod

altında
System.out.println(Integer.valueOf(b)); 

denerseniz Göreceksiniz 5 bunun için yönlendirilmesi sağlanır. Şimdi printf yöntemi için aşağıdaki kodun altındasınız.

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

Eğer printf görürseniz

ikinci parametre olarak ilk parametre ve nesne olarak Dize kabul eder. İlkel tür olarak b'ye sahipsiniz (int). Otomatik boks gerçekleşir ve bunun için Integer.java class method : valueOf(int i) kullanılır.

Ayrıca, Tamsayı bildirirseniz, otomatik kutulama olmadığı için her iki durumda da yazdırıldığını görürsünüz. genellikle -128 ila 127, önbelleğe alınır ve iç önbelleği değiştirdiniz. valueOf önbelleği kullanır ve farklı oputput'ları görmenizin sebebi de budur