java基本类型char

一、字符

基本类型char(Character对象封装的值), 占2个字节,最初可以用于表示unicode字符编码中一个字符,但是随着unicode标准的不断发展,已超出2个字节所能表达的字符数量范围0~65535。

unicode(统一码)是国际组织制定的可以容纳世界上所有文字和符号的字符编码方案。目前统一码用数字0-0x10FFFF来映射这些字符,最多可以容纳1,114,112个字符(码位),码位就是分配给字符的一一对应的数字。

数字转换到程序字节数据的编码方案,常见的有UTF-8、UTF-16、UTF-32等。

java中char值的编码是UTF-16,表示的是0~0xFFFF码位范围的字符,由于占2个字节,恰好用1个char表示。这些0~0xFFFF码位范围的字符,通常称为基本面BMP(Basic Multilingual Plane),它又简称为"零号平面"范围内的字符。

对于0x10000~0x10FFFF码位范围的字符,java用2个char来表示,此部分字符由unicode中一个被称作代理区(Surrogate)的特殊区域0xD800-0xDFFF处理, 目的是用两个UTF-16字符来表示BMP以外的字符。可以通过Character类封装的静态方法isSurrogate(char ch),来判断字符是否为代理区字符。

JDK1.8中char基于unicode标准版本6.2.0

二、字符串

String类包含属性 private final char value[];
它可以看做是对char[]数组的封装,String类一旦实例化,它的属性char[]就不可被改变。

三、汉字

unicode中"基本汉字"码位范围: 0x4E00~0x9FA5, 以及"基本汉字补充"码位范围: 0x9FA6~0x9FCB, 共20902 + 38 = 20940个字符,此外还有其他扩充、兼容的码位,这部分字符不常用。通常情况下,通过采用码位范围: 0x4E00~0x9FCB 来判断是否是汉字,就够了。

// 判断字符
public static boolean isChinese(char c) {		
	return (c >= '\u4E00' && c <= '\u9FCB');
}

// 判断字符串
static boolean isFindChinese(String value) {
	Pattern pattern = Pattern.compile("[\\u4E00-\\u9FCB]+");
	return pattern.matcher(value.trim()).find();		
}

四、全角/半角

半角
一个字符占用一个标准的字符位置,也就是ASCII范围内的可见字符,即unicode的码位为 0x21~0x7E, 以及空格 0x20范围内字符,以下是具体字符:

!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~

全角
一个字符占用两个标准的字符位置,例如中文,为让ASCII范围内可见字符,也占据等宽的空间,设计了全角模式, 对应unicode的码位 0xFF01~0xFF5E, 以及空格 0x3000范围内的字符, 以下是具体字符:

!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~

上面之所以把空格单独拎出来, 就是因为其他字符在位置上都是按顺序对应的,字符的全角、半角码位间隔固定:65248,而空格不知为何比较特殊。

    // 全角转半角
    public static String toHalfChar(String value) {
    	if (value == null || value.isEmpty()) return value;
    	
    	char[] arr = value.toCharArray();
    	for(int i = 0; i < arr.length; i++) {
			if (arr[i] == '\u3000') {
				arr[i] = '\u0020';
			} else if (arr[i] >= '\uff01' && arr[i] <= '\uff5e') {
				arr[i] = (char)(arr[i] - 65248);
			} 		
    	}
    	
    	return new String(arr);
	}

五、代理区(Surrogate)

常见的"表情符"等, 都是码位在0x10000~0x10FFFF范围内的字符,需要2个char来表示。

Character类的静态方法,可判断char是否属于代理区范围内的字符。
public static boolean isSurrogate(char ch)

属于代理区范围字符,在文本展示时,char必须成对,否则就是乱码。

例如:
String s1 = "\uD83D\uDE42";
System.out.println("s1: " + s1);
System.out.println("s1.length: " + s1.length());
System.out.println("s1.codePointCount: " + s1.codePointCount(0, 2));

运行结果:
s1: 🙂
s1.length: 2
s1.codePointCount: 1

六、序列化

字符的序列化就是按编码规则,将字符转换为对应的字节, 以方便数据的传递、持久化存储。

这就需要指定字符集 utf-8, utf-16, utf-32, gbk, gb2312等(base64当然也可以,本文仅讨论字符集间转换情况)。

因java中char本身就是utf-16编码,属于unicode编码标准,因此在序列化为utf系列字符集时,不存在丟数、乱码问题。但 gbk, gb2312 字符集的编码范围相对于unicode要小,对于它不支持的字符,例如"表情符"等,在转化时,就会出现这种丟数、乱码问题。

目前比较常见的utf-8编码,依据不同码位,占1~4个字节(其中1~3个字节的编码, 对应基本面BMP范围内字符)

MySQL在5.5.3之后增加了utf8mb4的编码支持,这是目前推荐的字符集,它的utf8字符集(仅支持1~3个字节的编码), 在存储BMP范围外字符时,同样会出现丟数、乱码问题。


常见乱码情况
1. 用错误的"字符集",来解读字节流, 网页上经常出现,采用正确的字符集就可以。
2. 就是上说的两个字符集固有的不兼容导致,这种情况不可调和,只能通过字符清洗、中间码转意解决。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值