[size=medium] 在java里一个字节是8位,char是两个字节即16位,相应的int是4个字节即32位。
一个UTF-8字符其实是UCS的实现形式,所以一般UTF-8只有三位,超过3位的则为一些象形文字之类。
首先需要明确的是计算机读取的所有东西均为字节,所以不管是什么字符最终均会转换成字节被读取。这样就引申出来一个问题:UTF-8这种多个字节的字符是怎么读取的?实际上这样的,计算机读取是顺序读取,也就是从左到右来顺序读取。于是聪明的设计者便用一种特殊的方式来实现UTF-8:
UTF-8一般有如下几种表现方式:
1个字节:0aaaaaaa
2个字节:110bbbbb 10aaaaaa
3个字节:1110cccc 10bbbbbb 10aaaaaa
因为计算机是顺序读取且读取的是字节,所以一个多位的字符,首先会被转成多个字节,接着计算机从高位字节往低位字节读取。
即如果一个字符是小于8位的,即是小于2<<7的,计算机读取到高位字节信息是以0开头时就不会进行额外运算,直接获取该字符,即其其实是一个ascii码字符。
接着是一个两个字节的字符,则计算机首先获取到的高位字节码是以110开头的,则计算机便知这是一个两个字节的字符,就会进行额外运算,将其与下一个字节进行联合运算,最终得到的字符其实是bbbbb aaaaaa.
同理一个三个字节的字符,最终得到的字符是cccc bbbbbb aaaaaa。
我们在自己实现对象持久化的时候,一般会将对象作为字节进行持久化。这时候便需要注意对char或者String(可以通过转成char保存,提供String的长度信息则可)进行保存时需要转码。
比如一个11011 100000的字符,其最终被保存成字节的时候则应该是11011011 1010000这样的两个字节。
则我们可以通过以下的算法来进行转码:
byte[] writeChars(char c) {
int code = c;
if (code <= 0x7F) {
return new byte[]{c};
} else if (code <= 0x07FF) {
return new byte[]{(byte)(0xC0 | ((code >> 6) & 0x1F)),(byte)(0x80 | code&0x3F)};
} else {
return new byte[]{(byte)(0xE0 | ((code >> 12) & 0X0F)),(byte)(0x80 | ((code >> 6) & 0x3F)),(byte)(0x80 | (code& 0x3F))};
}
}
这样就能保证字符持久化的正确性了。而读取的时候只要逆向运算就可以。
关于持久化的原理就留在后面再写了。[/size]
一个UTF-8字符其实是UCS的实现形式,所以一般UTF-8只有三位,超过3位的则为一些象形文字之类。
首先需要明确的是计算机读取的所有东西均为字节,所以不管是什么字符最终均会转换成字节被读取。这样就引申出来一个问题:UTF-8这种多个字节的字符是怎么读取的?实际上这样的,计算机读取是顺序读取,也就是从左到右来顺序读取。于是聪明的设计者便用一种特殊的方式来实现UTF-8:
UTF-8一般有如下几种表现方式:
1个字节:0aaaaaaa
2个字节:110bbbbb 10aaaaaa
3个字节:1110cccc 10bbbbbb 10aaaaaa
因为计算机是顺序读取且读取的是字节,所以一个多位的字符,首先会被转成多个字节,接着计算机从高位字节往低位字节读取。
即如果一个字符是小于8位的,即是小于2<<7的,计算机读取到高位字节信息是以0开头时就不会进行额外运算,直接获取该字符,即其其实是一个ascii码字符。
接着是一个两个字节的字符,则计算机首先获取到的高位字节码是以110开头的,则计算机便知这是一个两个字节的字符,就会进行额外运算,将其与下一个字节进行联合运算,最终得到的字符其实是bbbbb aaaaaa.
同理一个三个字节的字符,最终得到的字符是cccc bbbbbb aaaaaa。
我们在自己实现对象持久化的时候,一般会将对象作为字节进行持久化。这时候便需要注意对char或者String(可以通过转成char保存,提供String的长度信息则可)进行保存时需要转码。
比如一个11011 100000的字符,其最终被保存成字节的时候则应该是11011011 1010000这样的两个字节。
则我们可以通过以下的算法来进行转码:
byte[] writeChars(char c) {
int code = c;
if (code <= 0x7F) {
return new byte[]{c};
} else if (code <= 0x07FF) {
return new byte[]{(byte)(0xC0 | ((code >> 6) & 0x1F)),(byte)(0x80 | code&0x3F)};
} else {
return new byte[]{(byte)(0xE0 | ((code >> 12) & 0X0F)),(byte)(0x80 | ((code >> 6) & 0x3F)),(byte)(0x80 | (code& 0x3F))};
}
}
这样就能保证字符持久化的正确性了。而读取的时候只要逆向运算就可以。
关于持久化的原理就留在后面再写了。[/size]