2015-04-02 46 views
1

如果我將一個UTF-8字符轉換爲字節,那麼基於區域設置,環境等,這三種實現的結果是否會有所不同?單字節UTF-8到字節

byte a = "1".getBytes()[0]; 
byte b = "1".getBytes(Charset.forName("UTF-8"))[0]; 
byte c = '1'; 
+1

絕對。試試「UTF-16值大於127的任何字符」。考慮到*有超過255個字符,您怎麼可能期望在不丟失信息的情況下將'char'轉換爲'byte'? – 2015-04-02 19:19:56

+0

@JonSkeet那麼剛纔的127個字符呢? – tachyonflux 2015-04-02 19:50:37

回答

3

你的第一線取決於環境,因爲這將編碼使用系統的默認字符編碼,這可能是也可能不是UTF-8的字符串。

無論系統的語言環境或默認字符編碼是什麼,第二行總會產生相同的結果。它將始終使用UTF-8對字符串進行編碼。

請注意,UTF-8是一種可變長度字符編碼。只有前127個字符被編碼在一個字節中;所有其他字符將佔用2到6個字節。

您的第三條線將char投射到int。這將導致int包含字符的UTF-16字符代碼,因爲Java char存儲使用UTF-16的字符。由於UTF-16以與UTF-8相同的方式對字符進行部分編碼,因此結果與第二行相同,但對於任何字符而言通常都不是這樣。

1

原則上的問題已經回答了,但我無法抗拒張貼有點潦草,對於那些誰喜歡玩弄代碼:

import java.nio.charset.Charset; 

public class EncodingTest { 

    private static void checkCharacterConversion(String c) { 
     byte asUtf8 = c.getBytes(Charset.forName("UTF-8"))[0]; 
     byte asDefaultEncoding = c.getBytes()[0]; 
     byte directConversion = (byte)c.charAt(0); 
     if (asUtf8 != asDefaultEncoding) { 
      System.out.println(String.format(
       "First char of %s has different result in UTF-8 %d and default encoding %d", 
       c, asUtf8, asDefaultEncoding)); 
     } 
     if (asUtf8 != directConversion) { 
      System.out.println(String.format(
       "First char of %s has different result in UTF-8 %d and direct as byte %d", 
       c, asUtf8, directConversion)); 
     } 
    } 

    public static void main(String[] argv) { 

     // btw: first time I ever wrote a for loop with a char - feels weird to me 
     for (char c = '\0'; c <= '\u007f'; c++) { 
      String cc = new String(new char[] {c}); 
      checkCharacterConversion(cc); 
     } 
    } 
} 

如果你運行這個例如與:

java -Dfile.encoding="UTF-16LE" EncodingTest 

你將得不到輸出。 但當然,每一個字節(好吧,除了第一個)會,如果你嘗試是錯誤的:

java -Dfile.encoding="UTF-16BE" EncodingTest 

因爲在「大端」的第一個字節始終是ASCII字符爲零。 這是因爲在UTF16 ASCII字符'\u00xy由兩個字節表示的,在UTF16-LE如[xy, 0]和UTF16-BE爲[0, xy]

但是隻有第一個語句產生任何輸出,所以bc確實對於前127個ASCII字符也是如此 - 因爲在UTF-8中它們由單個字節編碼。然而,對於任何其他人物來說,這不會是真的。它們都使用UTF-8進行多字節表示。