美文网首页
Java编码总结

Java编码总结

作者: 玉圣 | 来源:发表于2020-06-21 08:50 被阅读0次

    一、编码概念总结:

    1、概念:

    字符集(character set):是一个系统支持的所有抽象字符的集合。
    字符(character):是各种文字和符号,包括国家文字、标点符号、图形符号、数字等。

    2、常见字符集:

    字符集规定了符合对应的二进制代码,至于这个二进制代码如何存储则没有任何规定。就是为每个字符规定一个用来表示该字符的数字,仅此而已。
    是一种字符编码规范

    • Unicode:也叫统一字符集,它包含了几乎世界上所有的已经发现且需要使用的字符(如中文、日文、英文、德文等)。
    • ASCII:早期的计算机系统只能处理英文,所以ASCII也就成为了计算机的缺省字符集,包含了英文所需要的所有字符。
    • GB2312:中文字符集,包含ASCII字符集。ASCII部分用单字节表示,剩余部分用双字节表示。
    • GBK:GB2312的扩展,完整包含了GB2312的所有内容。
    • GB18030:GBK字符集的超集,常叫大汉字字符集,也叫CJK(Chinese,Japanese,Korea)字符集,包含了中、日、韩三国语言中的所有字符。

    3、常见编码方式:

    • UTF-8(Unicode字符集的编码方式)
    • UTF-16(Unicode字符集的编码方式)
      用2个字节为字符编码,可表示的字符数为2^16=65535
    • UTF-32(Unicode字符集的编码方式)
      用4个字节为字符编码(实际上只用了31位,最高位必须为0),有2^31=2147483648个码位
    • ASCII(ASCII字符集的编码方式)

    4、其他:

    • ASCII
      是用来表示英文字符的一种编码规范,每个ASCII字符占用1个字节(8bits)
      ASCII编码可以表示的最大字符数是256

    • UTF:UCS Transformation Format,UCS转换格式
      它是将Unicode编码规则和计算机的实际编码对应起来的一个规则。现在流行的UTF有2种:UTF-8和UTF-16 。
      UTF-16和Unicode本身的编码规范(UCS-2(Unicode-16))是一致的
      UTF-8定义了一种“区间规则”,这种规则可以和ASCII编码保持最大程度的兼容 。

    • UTF-8有点类似于Haffman编码,它将Unicode编码为
      00000000-0000007F的字符,用1 个字节表示
      00000080-000007FF的字符,用2 个字节表示
      00000800-0000FFFF的字符,用3 个字节表示

    目前为止Unicode-16规范没有指定FFFF以上的字符,所以UTF-8最多是使用3个字节来表示一个字符。但理论上来说,UTF-8最多需要用6字节表示一个字符。

    5、中文编码:

    国际上制定了针对中文的统一字符集GBK和GB18030,其中GBK已经在Windows、Linux等多种操作系统中被实现。

    • GBK兼容GB2312,并增加了大量不常用汉字,还加入了几乎所有的Big5中的繁体汉字。但是GBK中的繁体汉字和Big5中的几乎不兼容。
    • GB18030相当于是GBK的超集,比GBK包含的字符更多。据我所知目前还没有操作系统直接支持GB18030。

    二、计算机中的编码:

    1、说明:

    • 字符必须编码后才能被计算机处理。
    • 内码:计算机使用的缺省编码方式就是计算机的内码。
    • 按照程序员的称呼,GB2312、GBK到GB18030都属于双字节字符集 (DBCS)。
      在DBCS中,GB内码的存储格式始终是big endian,即高位在前。
      GB2312的两个字节的最高位都是1。但符合这个条件的码位只有128*128=16384个。所以GBK和GB18030的低字节最高位都可能不是1。不过这不影响DBCS字符流的解析:在读取DBCS字符流时,只要遇到高位为1的字节,就可以将下两个字节作为一个双字节编码,而不用管低字节的高位是什么。

    2、编码规则:

    编码规则

    根据上面编码规则对照表,进行 UTF-8 编码和解码就简单多了。下面以汉字“汉”为利,具体说明如何进行 UTF-8 编码和解码。

    “汉”的 Unicode 码点是 0x6c49(110 1100 0100 1001),通过上面的对照表可以发现,0x0000 6c49 位于第三行的范围,那么得出其格式为 1110xxxx 10xxxxxx 10xxxxxx。接着,从“汉”的二进制数最后一位开始,从后向前依次填充对应格式中的 x,多出的 x 用 0 补上。这样,就得到了“汉”的 UTF-8 编码为 11100110 10110001 10001001,转换成十六进制就是 0xE6 0xB7 0x89。

    解码的过程也十分简单:如果一个字节的第一位是 0 ,则说明这个字节对应一个字符;如果一个字节的第一位1,那么连续有多少个 1,就表示该字符占用多少个字节。


    示例

    三、Java中的字符编码和字符集

    1、char字符

    • Java中char类型是16位无符号基本数据类型,用来存储Unicode字符,使用UTF-16编码描述一个代码单元。
    • Unicode代码点的合法范围是 :U+0000到U+10FFFF
      U+0000到U+FFFF称为Basic Multilingual Plane(BMP)
      代码点大于U+FFFF的字符称为增补字符,2个char:一个为高位,一个为低位。

    2、String字符串

    • Java字符串由char序列组成
    • String类型的length方法,它返回的是UTF-16编码表示的给定字符串的代码单元的数量
      如果想要得到代码点的数量,可以调用codePointCount()方法,charAt方法返回位于指定位置的代码单元,codePointAt方法则返回指定位置的代码点。
    • Java代码需要编译成class文件后由JVM运行,在class文件里,字符串使用UTF-8编码,保存于常量池中。

    4、Big Endian,Little Endian与文本开头的标志

    • 一个字符可能占用多个字节,比如字符0xABCD,如果存储为AB CD,则称为Big Endian;如果存储为 CD AB,则称为Little Endian。
    • 要知道具体是哪种编码方式,需要判断文本开头的标志:


      image.png

    5、字节流与字符流

    • InputStream为字节输入流的所有类的超类
    • Reader为读取字符流的抽象类
    • java读取文件的方式分为按字节流读取和按字符流读取,其中InputStream、Reader是这两种读取方式的超类。
    • 其实字符流可以看做是一种包装流,它的底层还是采用字节流来读取字节,然后它使用指定的编码方式将读取字节解码为字符。在读取的时候字符读取每次是读取2个字节,字节流每次读取1个字节。

    四、相关面试题:

    1、Java中的char是两个字节,如何存UTF-8字符?

    • char是两个字节(16位),是用UTF-16来存储一个代码单元,而UTF-8是可变编码方式,存1到3个字节
    • UTF-8是Unicode字符集的一种常见的编码方式,另一种常见的编码方式是UTF-16(最小单位是2个字节)。


      如何存储字符
    • Unicode通用字符集占两个字节,如“中”
    • Unicode扩展字符集就需要用一对char来表示,如表情“😎”
    • Java中的String的length得到的不是字符数,而是字节数
    • 比如“中”这个字符串,以“UTF-16”的编码方式获得的length长度为4,其中前两个字节表示的是字节序标记,说明是后两个字节要一起解析。
      image.png
      具体的例子见:结合Java详谈字符编码和字符集
      Java9中对字符串做了些优化,字符串长度和字符数不一致未做处理,对字符存储空间做了优化,对Latin(拉丁)字符,还用UTF-16存储,就浪费了一半的空间,就用byte存,就可以节省一半的空间。

    资料:
    Java:Unicode简介
    彻底弄懂 Unicode 编码
    结合Java详谈字符编码和字符集
    java编码之BASE64
    Java中的字节,字符与编码,解码
    Java Unicode编码系统

    相关文章

      网友评论

          本文标题:Java编码总结

          本文链接:https://www.haomeiwen.com/subject/hitgxktx.html