JAVA学习脚印10:解惑java 中UTF-16与char

java中的char、utf-16编码、代码点、代码单元等概念,做一个了解还是有必要的。

1.基本概念

1) Java的字符类型和字符串类型

字符类型采用的是UTF-16编码方式对Unicode编码表进行表示。其中一个char类型固定2字节,为无符号数,表示范围为'\u0000'(0)~'\uffff'(65,535)。

java中的String定义如下:

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final char value[];

...

}

可见String内部使用char来存储字符的,且是不可变的,即java字符串是由char序列组成。

2) Unicode编码表的专业术语:

a.  代码点 (code point): 指在Unicode编码表中一个字符所对应的代码值。如汉字“一”的代码点是U+4E00,英文字母“A”的代码点是U+0041。

b.  代码单元( code unit): 规定16bits的存储容量就是一个代码单元。java中的一个字符char就对应一个代码单元,大多数uncode字符使用一个代码单元就够了,而辅助字符(见下文)需要一对代码单元。

可以这样构造字符数据:

如 char[] chs = {'\u2764','\u2602','\u2600','\u262F','\u262D','\u2622','\u260E'};

上面这几个字符比较流行,在GUI Jlabel中彩色打印出来如下图所示:

可以通过网站: http://unicode-table.com/en/#control-character

来获取你想要的unicode字符。

c.  代码级别 (code plane): Unicode编码表 ,分为17个代码级别 (code plane),其中代码点U+0000-U+FFFF为第一级别 ——基本多语言级别 (basic multiling l plane),可以用一个代码单元存储一个代码点。其余16个附加级别 从0x10000-0x10FFFF(需要两个代码单元)。

其中需要指出的是在多语言级别中,U+D800-U+DFFF这2048值没有表示任何字符,被称为Unicode的替代区域(surrogate area)。UTF-16正是的运用了这一区域,用2个代码单元(2*16bits)巧妙的表示出20bits代码点的Unicode附加级别。

3)UTF-16编码算法

假设U是一个代码点,也就是Unicode编码表中一个字符所对应的Unicode值。
       1) 如果U<U+10000,也就是处于Unicode的基本多语言级别中。这样16bits(一个代码单元)就足够表示出字符的Unicode值。
       2) 如果U+10FFFF>U>=U+10000,也就是处于附加级别中。UTF-16用2个16位来表示出了,并且正好将每个16位都控制在替代区域U+D800-U+DFFF 中了。

附加级别中的编码具体操作如下:

分别初始化2个16位无符号的整数 —— W1和W2。其中W1=110110yyyyyyyyyy(0xD800-0xDBFF),W2 = 110111xxxxxxxxxx(0xDC00-OxDFFF)。

U' = U - 0x10000(注意,网上很多博客中关于这个算法的存在错误,错误之处就是没有减去0x10000).

然后,将U'的高10位分配给W1的低10位,将U'的低10位分配给W2的低10位。这样就可以将20bits的代码点U拆成两个16bits的代码单元。

而且这两个代码点正好落在替代区域U+D800-U+DFFF中。而且w1和w2具有可区分性,0xD800-0xDBFF属于高代理项(high-surrogate),0xDC00-OxDFFF属于低代理项(high-surrogate)。

2.实例说明

这里举一个网上很多博客提到的比较经典的例子,U+1D56B:

该字符可以在 http://www.scarfboy.com/coding/unicode-tool?

网站上输入代码点后查看,看起来是这样的,

假设U = U+1D56B ,则U属于附加级别中的附加字符,那么可如下计算编码:

Step1:

U' = U- 0x10000 = 0x0D56B

=   0000 1101 0101 0110 1011

Step2 :

U'高十位:  0000 1101 01

U'低十位:  01 0110 1011

则w1 = 1101 1000 0011 0101  = 0xD835

w2 = 1101 1101 0110 1011  = 0xDD6B

至此将U+1D56B 编码为两个代码单元,第一个为0xD835,第二个为 0xDD6B 。

下面的代码可以加深对上述概念的理解:

package com.liucaijin.springboot2;public class UTF16Test {public static void main(String[] args) {String sample = null;if(args.length > 0) {sample = args[0];} else {// for the sake of not show the character of u+1D56BString special = new String(Character.toChars(0x1D56B));sample = special+" zZ" + special;}System.out.println("sample string is:  "+sample);// String.length : Returns the length of this string.// The length is equal to the number of Unicode code units in the string.int len = sample.length();System.out.println("code units count:  "+len);// traverse the string by code unitsSystem.out.print("code units are:  ");UTF16Test.traverseByCodeUnits(sample);System.out.println();// get the number of Unicode code pointsint cpCount = sample.codePointCount(0, len);System.out.println("code points count:  "+cpCount);// traverse the string by code point sSystem.out.print("code points are:  ");UTF16Test.traverseByCodePoints(sample);System.out.println();}/*** traverse the string by code points* @param str the specified string to traverse*/public static void traverseByCodePoints(String str) {int cpCount =  str.length();boolean flag = false;for(int ix = 0;ix < cpCount;ix++) {flag = printCodePoint(str.codePointAt(ix),flag);}}/*** traverse the string by code units* @param str the specified string to traverse*/public static void traverseByCodeUnits(String str) {int cuCount = str.length();for(int ix = 0;ix < cuCount;ix++) {String content = String.format("(%04x)  ",(int)str.charAt(ix)).toUpperCase();System.out.print(content);//get code unit}}/*** print code point in hexadecimal form* @param cp the code point*/private static boolean printCodePoint(int cp,boolean flag) {//check if is the supplementary code pointif(Character.isSupplementaryCodePoint(cp)) {char[] chs = Character.toChars(cp);//stored the code point in  UTF-16 representationString content = String.format("[U+%04x,U+%04x]  ",(int)chs[0],(int)chs[1]).toUpperCase();System.out.print(content);return true;} else if(!flag) {String content = String.format("[U+%04x]  ",cp).toUpperCase();System.out.print(content);return false;}return false;}}

不带参数时运行结果为 :

更多关于字符和字符串的操作可参考java官方API.

本文参考了博客:blog.csdn.net/fantasy0126/article/details/6050087

JAVA学习脚印10:解惑java 中UTF-16与char相关推荐

  1. JAVA学习脚印3: java语言控制流程

    JAVA学习脚印3: java语言控制流程 本节首先介绍,java语言中的字符串处理以及输入输出控制,最后介绍控制流程. 在讲述控制流程之前,先介绍以下java中字符串和输入输出的内容,以便后续练习编 ...

  2. JAVA学习脚印2: 数据类型和运算符

    JAVA学习脚印2: 数据类型和运算符 本节将记录java中的数据类型和运算符. 1. java中的数据类型 java中变量的数据类型有两种:基本类型(primitive)和引用(reference) ...

  3. JAVA java学习(9)——————java常用开发工具介绍

    下面这些工具或许功能和作用不同,但是有着一个共同的主旨,那就是--它们都是为了给 Java 编码和开发提供卓越的支持. 常用源码编辑工具介绍 ava 源代码本质上其实就是普通的文本文件,所以理论上来说 ...

  4. [Java学习探讨]为什么学Java虚拟机的Java程序员更有价值?

    个人博客导航页(点击右侧链接即可打开个人博客):大牛带你入门技术栈 [Java学习探讨]为什么学Java虚拟机的Java程序员更值钱? 曾经的我经常害怕处理与JVM相关的异常,对JVM的配置参数也一无 ...

  5. springboot毕设项目java学习平台m55rv(java+VUE+Mybatis+Maven+Mysql)

    springboot毕设项目java学习平台m55rv(java+VUE+Mybatis+Maven+Mysql) 项目运行 环境配置: Jdk1.8 + Tomcat8.5 + Mysql + HB ...

  6. Java学习系列(十八)Java面向对象之基于UDP协议的网络通信

    UDP协议:无需建立虚拟链路,协议是不可靠的. A节点以DatagramSocket发送数据包,数据报携带数据,数据报上还有目的目地地址,大部分情况下,数据报可以抵达:但有些情况下,数据报可能会丢失 ...

  7. Java学习系列(十六)Java面向对象之基于TCP协议的网络通信

    TCP/IP的网络分层模型:应用层(HTTP/FTP/SMTP/POPS...),传输层(TCP协议),网络层(IP协议,负责为网络上节点分配唯一标识),物理层+数据链路层). IP地址用于标识网络中 ...

  8. Java学习练习题08:Java习题及代码08

    Java学习练习题08: Java习题及代码08: 链接:https://pan.baidu.com/s/1_PCPo7SI2fRFph02l2UCpQ  提取码:zapx

  9. JAVA学习 11.10

    Java第一天 1.1 Java发展史 1995年,SUN虽然推出了Java . 詹姆斯 高瑟林[java之父]带领自己的团队研发了java编程语言. 后来有一个公司就整了一个开发软件 Eclipse ...

最新文章

  1. 数据缺失、混乱、重复怎么办?最全数据清洗指南
  2. 脚本修改linux网络配置,用脚本实现Linux的网络配置
  3. 实例详细讲解ASP生成静态页面方法
  4. 香港大学顾佳涛:非自回归神经机器翻译 | 直播预告
  5. .NET程序员应该理解的几种软件保护方法 辛苦开发的程序需要建立有效的保护机制...
  6. python34.dll_python34.dll下载
  7. python实例 85,86
  8. java 十进制 左移,java移位运算符之十进制转二进制
  9. 易语言注入 c dll,易语言DLL注入模块简单型
  10. 关于升级Vmware ESXI6.7 主机挂在ISCSI共享存储的方法
  11. java加载阶段内存分配_Java核心:类加载和JVM内存的分配
  12. C++ 对Ctrl+Z的解释
  13. GOM引擎ItemShow代码在NPC对话框中显示装备图片及属性
  14. 百度C语言面试题2017,百度C语言面试题
  15. 【位操作笔记】计算以10为底整数N的对数 普通方法
  16. 内网穿透到cs上线--部署到公网上!!
  17. 基于HTML贪吃蛇游戏摘要,基于JavaScript实现贪吃蛇游戏
  18. 介绍一种冷门但简单的双拼方案——紫光双拼
  19. between oracle的用法,关于 oracle between and的用法! | 学步园
  20. 苹果M1 Mac 如何卸载 iPhone 和 iPad 应用程序?

热门文章

  1. 亚洲上海linux_亚洲企鹅将程序变成Linux的成功
  2. Unity--地形编辑
  3. 正确把握客户关系管理
  4. 从极度贫困到财务自由(转贴
  5. 服务架构:统一身份认证和授权技术解决方案
  6. 计算机基础第1课:计算机发展史
  7. 荣耀20android版本,荣耀20青春版是什么处理器 荣耀20青春版处理器是哪一款
  8. Google Noto Fonts:兼容所有语言的字体
  9. rtx4060ti参数 rtx4060ti功耗 rtx4060相当于什么水平
  10. 2021-08-02