这是我参与更文挑战的第6天,活动详情查看: 更文挑战
最近在做文件解析的时候总是看到FILE,BUFFER,STREAM,就很苦恼,为此我就想从他们的编码格式来看看他们是如何解析文件的;
字节、字符,哎!!!为了引起大家兴趣;我先抛出一个JDK优化的问题(问题一抛可能就没篇幅写文件流了,哎),可能有人注意到,有人没有注意到;
那就是String大哥,在jdk1.8的时候看下String的源码,它是以char数组来存储数据的;
private final char value[];
复制代码
在jdk11的时候,他是以byte来存储数据的(JDK9开始)
@Stable //@Stable表示该数组不会为null,final表示字符串一旦被初始化后是不会被改变的。
private final byte[] value;
复制代码
为什么String要做这个改动呢?
我们先来了解一下char(字符)和byte(字节)
一个字符=2个字节,,一字节占8位,所以一个char占16位=16bit;
好,这是我们的固有认知,我们看下jdk8对String字符的描述:
String表示 UTF-16 格式的字符串,其中增补字符由代理对表示(有关更多信息,请参阅Character类中的Unicode 字符表示部分)。 索引值指的是char代码单元,因此增补字符使用String两个位置。 除了用于处理 Unicode 代码单元(即char值)的方法之外, String类还提供了用于处理 Unicode 代码点(即字符)的方法
官方这里把char称为代码单元code unit,既然String是_UTF-16 格式的字符串,_那么我们看下他存储的数据在_UTF-16 格式_下占几个字节
String name="name";
复制代码
不少人估计都会认为,哎呀,那不得八位吗,一个字符占两个字节嘛,打出来我就傻眼了;它占了十个字节,多了两个,难道C语言来了加了个\n?,哈哈,我搜了很久,原因是UTF-16文件的头2个字节里做个标记LE [0xFF, 0xFE], BE [0xFE, 0xFF],如果你用UTF_16BE或UTF_16LE那么打出来的字节数会是8;有点跑题哈~~~
我们再来看下jdk9用byte来处理的官方解释,支持两种编码_LATIN1(ISO-8859-1)和UTF-16,_虚拟机会根据相应的内容来选择使用哪种编码,Latin-1是用单个字节来表示字符的,比utf-16的两个字节少了一半空间。 当然怎么选择哪种编码呢?所以String类中多了一个编码标志位coder,用来表示使用的是utf-16编码,还是Latin-1编码
private final byte coder;
复制代码
ISO-8859-1收录的字符除ASCII收录的字符外,还包括西欧语言、希腊语、泰语、阿拉伯语、希伯来语对应的文字符号,注意,这里不包括中文等字符,所以必须保留UTF-16来适应不同字符;
我们日常开发的时候String保留的很多都是单字节的,不会说无缘无故定义一个中文的。一般都是字母或者数字,这样只需_LATIN1_单字节即可了,没必要用char浪费,但对于少量的中文赋值就只能用char来存储了;
在写这篇文章的时候发现一个小插曲,java设计者本来想用UTF-16前身UCS-2来表示unicode(统一码、万国码、单一码)中的所有字符,但是后来Unicode太大了,两个字节也就不够用了,所以char的定义也就变了,不再是字符了,而是代码单元,最早一批收录的字符后来被叫作Basic Multilingual Plane(BMP),然后编码表使用utf-16;,所以单个char只能描述unicode中的BMP范围的码位,BMP外的字符char无法表示;所以现在的UTF-16是不定长的
既然char占两个字节,定长的,那么如何表示四个字节的字符呢,比如表情emoji 情等,那就是用两个char(注意得用String接收呦),**点明前面的说char是代码单元,**目前四个字节在现在可以表示所有!所以java中不能用char表示BMP外内容哦;虽然大部分情况我们不会考虑这些;
突然我上面好像也没跑题呦~~~
所以为什么改为byte知道了吧,主要就是优化内存空间,优化靠什么,单字符的_LATIN1_,又保证不影响原来的使用,所以保留UTF-16;在我们调用length()方法时依然计算的是char(代码单元),
***千万不要混淆哦,只是编码方式变了,而编码才决定占用字节多少,该怎么读长度还是怎么读长度***
name 使用iso-8859-1,四个字节,所以是4
我们 使用UTF-16 BMP范围内,四个字节,两个char 所以是2
name我们 使用UTF-16 12个字节,这里注意,因为是UTF-16编码,所以name里每个字符依然占两个字节,和汉字一样,
6个char,所以长度是6
复制代码