1. 程式人生 > >你的環境有問題吧?--byte陣列轉字串的疑惑

你的環境有問題吧?--byte陣列轉字串的疑惑

1. 故事背景

小T是個測試MM,小C是個程式猿,今天早上他們又為一個bug吵架了。

小T:“這個顯示是bug,在我的瀏覽器上顯示不正確”

 

小C:“這個bug我不認,在我的電腦上顯示正常,是你的環境有問題吧?”

小T:“我不管,反正我這個顯示不正確,就是個bug”

小C:“我。。。。。。。。。。。。。。。。。”

最終leader出面,大家做到一起查詢問題。(為防止公司資訊洩露,下面為模擬程式)

    public static void main(String[] args) throws UnsupportedEncodingException {
        byte bytes[] = new byte[256];
        for (int i = 0; i < 256; i++)
        bytes[i] = (byte)i;
        String str = new String(bytes);
        for (int i = 0, n = str.length(); i < n; i++)
        System.out.print((int)str.charAt(i) + " ");
    }

小T首先展示程式輸出:

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 
65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533 65533

小C也不甘示弱,在自己的電腦上執行,得到如下結果:

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255

leader檢查了小C和小T的程式後,發現程式完全一樣,為什麼會出現這種情況呢?

2. 事故查詢

經debug發現,小T和小C的程式在

String str = new String(bytes);

這段程式碼時發生了不同:

小C的程式碼str為:

 

小T的程式碼為:

 

其中65533的圖片顯示為:

 

推測可能是編碼問題,深入其原始碼內部,看看

 /**
 * Constructs a new {@code String} by decoding the specified array of bytes
 * using the platform's default charset. The length of the new {@code
 * String} is a function of the charset, and hence may not be equal to the
 * length of the byte array.
 *
 * <p> The behavior of this constructor when the given bytes are not valid
 * in the default charset is unspecified. The {@link
 * java.nio.charset.CharsetDecoder} class should be used when more control
 * over the decoding process is required.
 *
 * @param bytes
 * The bytes to be decoded into characters
 *
 * @since JDK1.1
 */
 public String(byte bytes[]) {
 this(bytes, 0, bytes.length);
 }

 

翻譯過來就是:在通過解碼使用平臺預設字符集的指定byte 陣列來構造一個新的String 時,該新String 的長度是字符集的一個函式,因此,它可能不等於byte 陣列的長度。當給定的所有位元組在預設字符集中並非全部有效時,這個構造器的行為是不確定的。

罪魁禍首就是String(byte[])構造。

3. 問題解決

小C承認了自己的錯誤,小T也高興得提了個bug。接下來小C就要修改掉這個bug了。

    public static void main(String[] args) throws UnsupportedEncodingException {
        byte bytes[] = new byte[256];
        for (int i = 0; i < 256; i++)
        bytes[i] = (byte)i;
        String str = new String(bytes,"ISO-8859-1");
        for (int i = 0, n = str.length(); i < n; i++)
        System.out.print((int)str.charAt(i) + " ");
    }

 

指定字符集後,小T和小C又能愉快得玩耍了。

總結

每當你要將一個byte 序列轉換成一個String 時,你都在使用某一個字符集,不管你是否顯式地指定了它。如果你想讓你的程式的行為是可預知的,那麼就請你在每次使用字符集時都明確地指定。

參考資料:

【1】java解惑

【2】https://www.jianshu.com/p/52fd2a304228

【3】http://www.mytju.com/classcode/tools/encode_utf8