1. 故事背景

小T是个测试MM,小C是个程序猿,今天早上他们又为一个bug吵架了。

小T:“这个显示是bug,在我的浏览器上显示不正确”

你的环境有问题吧?--byte数组转字符串的疑惑

 

小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为:

你的环境有问题吧?--byte数组转字符串的疑惑

 

小T的代码为:

你的环境有问题吧?--byte数组转字符串的疑惑

 

其中65533的图片显示为:

你的环境有问题吧?--byte数组转字符串的疑惑

 

推测可能是编码问题,深入其源码内部,看看

 /**
 * 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.asp

posted on 2019-10-10 16:53  一天不进步,就是退步  阅读(721)  评论(0编辑  收藏  举报