《Java解惑》系列——02字符谜题——谜题18:字符串奶酪(new String(byte [] b))

知识点:

在使用String的String(byte[])是,一定要指定编码。否则,他会使用平台默认的缺省编码,这样非常容易引起混乱。


问题:

下面的程序会打印社么?

public class StringCheese { 
    public static void main(String[] args) { 
        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.println((int)str.charAt(i) + " ");
        }
    } 
} 

// 期望结果:0到255,解决方法使用new String(bytes, 'ISO-8859-1')
// 实际结果:不同的平台,打印的结果有所查询。


结果是不是出乎大家的意料呢?的确如此。
产生这个结果的原因:

首先,byte 数组用从0到 255每一个可能的 byte 数值进行了初始化,然后这些
byte 数值通过String构造器被转换成了 char 数值。最后,char 数值被转型为
int 数值并被打印。打印出来的数值肯定是非负整数,因为 char 数值是无符号
的,因此,你可能期望该程序将按顺序打印出0 到 255的整数。  
如果你运行该程序,可能会看到这样的序列。但是在运行一次,可能看到的就不
是这个序列了。我们在四台机器上运行它,会看到四个不同的序列,包括前面描
述的那个序列。这个程序甚至都不能保证会正常终止,比打印其他任何特定字符
串都要缺乏这种保证。它的行为完全是不确定的。  
这里的罪魁祸首就是String(byte[])构造器。有关它的规范描述道:“在通过
解码使用平台缺省字符集的指定 byte 数组来构造一个新的String时,该新
String的长度是字符集的一个函数,因此,它可能不等于 byte 数组的长度。当
给定的所有字节在缺省字符集中并非全部有效时,这个构造器的行为是不确定
的”[Java-API]。 
到底什么是字符集?从技术角度上讲,它是“被编码的字符集合和字符编码模式
的结合物”[Java-API]。换句话说,字符集是一个包,包含了字符、表示字符的
数字编码以及在字符编码序列和字节序列之间来回转换的方式。转换模式在字符
集之间存在着很大的区别:某些是在字符和字节之间做一对一的映射,但是大多
数都不是这样。ISO-8859-1 是唯一能够让该程序按顺序打印从0 到 255的整数
的缺省字符集,它更为大家所熟知的名字是Latin-1[ISO-8859-1]。 



解决方法:

ISO-8859-1 是唯一能够让该程序按顺序打印从0 到 255的整数的缺省字符集,它更为大家所熟知的名字是Latin-1[ISO-8859-1]。 

J2SE运行期环境(JRE)的缺省字符集依赖于底层的操作系统和语言。如果你想
知道你的 JRE的缺省字符集,并且你使用的是5.0 或更新的版本,那么你可以通
过调用java.nio.charset.Charset.defaultCharset()来了解。如果你使用的是
较早的版本,那么你可以通过阅读系统属性“file.encoding”来了解。  
幸运的是,你没有被强制要求必须去容忍各种稀奇古怪的缺省字符集。当你在
char 序列和 byte 序列之间做转换时,你可以且通常是应该显式地指定字符集。
除了接受byte 数字之外,还可以接受一个字符集名称的String构造器就是专为
此目的而设计的。如果你用下面的构造器去替换在最初的程序中的String构造
器,那么不管缺省的字符集是什么,该程序都保证能够按照顺序打印从0 到 255
的整数:
 


总结:

这个谜题的教训是:每当你要将一个 byte 序列转换成一个String时,你都在使
用某一个字符集,不管你是否显式地指定了它。如果你想让你的程序的行为是可
预知的,那么就请你在每次使用字符集时都明确地指定。对 API的设计者来说,
提供这么一个依赖于缺省字符集的String(byte[])构造器可能并非是一个好主
意。 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值