2017-04-06 45 views
3

我正在玩String及其構造函數,並注意到我無法解釋的一些行爲。「否定」一個字符串會產生意想不到的行爲

我創建了以下方法

public static String negate(String s) { 
    byte[] b = s.getBytes(); 
    for (int i = 0; i < b.length; i++) { 
     b[i] = (byte)(~b[i] + 1); 
    } 
    System.out.println(Arrays.toString(b)); 
    return new String(b); 
} 

它只是做了2對每個byte補充,並返回一個新的String。當調用它像

System.out.println(negate("Hello")); 

我的

[-72, -101, -108, -108, -111] 
����� 

我的猜測是好的,因爲有沒有負面的ASCII值的輸出。
但是,當我嵌套調用像這樣

System.out.println(negate(negate("Hello"))); 

我的輸出是這樣

[-72, -101, -108, -108, -111] 
[17, 65, 67, 17, 65, 67, 17, 65, 67, 17, 65, 67, 17, 65, 67] 
ACACACACAC // 5 groups of 3 characters (1 ctrl-char and "AC") 

我預計輸出精確匹配我的輸入字符串"Hello",而是我得到這個。爲什麼?每個其他輸入字符串也會發生這種情況。嵌套之後,輸入中的每個單個字符只會變成AC

我越走越創建做同樣的事情的方法,而只用原料byte陣列

public static byte[] n(byte[] b) { 
    for (int i = 0; i < b.length; i++) { 
     b[i] = (byte)(~b[i] + 1); 
    } 
    System.out.println(Arrays.toString(b)); 
    return b; 
} 

這裏是否如預期的輸出。對於

System.out.println(new String(n(n("Hello".getBytes())))); 

我得到

[-72, -101, -108, -108, -111] 
[72, 101, 108, 108, 111] 
Hello 

所以我想它做String s的創建方式,因爲它只有當我叫negate與已經得到了負byte秒的情況下發生?

我甚至走下類樹看內部類,但我無法找到這種行爲來自哪裏。

另外在String的文檔有以下段落,這可能是一個解釋:

此構造函數時給出的字節是不是在默認字符集有效的行爲是不確定的

燦有人告訴我爲什麼它是這樣的,到底發生了什麼?

+5

嗯,是的 - 你試圖解釋這彷彿他們正在編碼的文本實際上並沒有編碼的文本任意字節。我強烈建議你不要這樣做。 –

+0

如果使用映射256個字節(如ISO-8859-1例如)字符集,它的工作原理與第一種方法 – aurya

+0

而且,沒有什麼你正在做包括ASCII。 [String.getBytes()](https://docs.oracle.com/javase/7/docs/api/java/lang/String.html#getBytes())可以作出但其目的是非常具體的:爲了根據計算機操作系統用戶的當前設置而有所不同。在我工作的任何域中都沒有用。 –

回答

4

問題是你正在採取反轉字節,並試圖將它們解釋爲默認字符集中的有效字節流(請記住,字符不是字節)。所以,當你引用的字符串構造文檔告訴你,結果不確定,且可能涉及糾錯,丟棄無效值,等等,等等。當然,那麼,這是一個有損過程,並扭轉它不會讓你回你原始字符串。

如果你得到的字節和雙重否定沒有轉換中間字節爲字符串,你會回來你的原始結果。

此示例演示的new String(/*invalid bytes*/)有損性質:

String s = "Hello"; 
byte[] b = s.getBytes(); 
for (int i = 0; i < b.length; i++) { 
    b[i] = (byte)(~b[i] + 1); 
} 
// Show the negated bytes 
System.out.println(Arrays.toString(b)); 
String s2 = new String(b); 
// Show the bytes of the string constructed from them; note they're not the same 
System.out.println(Arrays.toString(s2.getBytes())); 

在我的系統,我相信默認爲UTF-8,我得到:

 
[-72, -101, -108, -108, -111] 
[-17, -65, -67, -17, -65, -67, -17, -65, -67, -17, -65, -67, -17, -65, -67] 

注意,當我把發生的事無效的字節流,從中取出一個字符串,然後獲取該字符串的字節。

2

你「否定」一個字符,它變得無效。然後你得到佔位符(U + FFFD)。此時一切都已損壞。然後你「否定」那個,並且你從每個佔位符字符中獲得你的AC

+0

嗯,這取決於。 UTF-8不是任何地方的默認字符集。 –

+0

嗯,不過,這裏就是這種情況,我不想將它擴展到「編碼工作如何」的答案。 – Kayaman

相關問題