Java char类型介绍

前言:最近,想写一篇关于介绍产生”乱码问题“根本原因的文章,因此,查看了Java中的字符是如何存储的,即char数据类型。在此将学到的知识做一个总结。

一、char数据类型
char类型最初用于表示Unicode字符集中的一个字符,但是随着Unicode标准的不断发展,其字符集不断扩展,表示的字符随之增加,已经超出了16位的char类型可以表示的范围(65535),现今,char类型用于表示一个代码单元。有些Unicode字符需要使用一个代码单元表示,有些Unicdoe字符需要两个代码单元表示。关于代码单元的概念,下文会详细介绍,这里先有一个印象即可。

1. 字面量值
字面量值需要单引号''括起来,单引号中必须有值,其形式如下:

单个Unicode字符,最常见的形式,例如,'A'、'中';
转义序列\u,范围\u0000~\uFFFF,例如, '\u2122' 表示字符™,'\u03C0'表示字符'π';
特殊字符的转义序列,例如'\n'表示换行,'\''表示单引号。
转义字符,一般是不可打印的或者与语言的语法字符产生了冲突。

二、Unicode字符集
1. 字符集和编码规则
我们经常会听到Unicode、UTF-8、UTF-16这些术语,然而,它们是完全不同的概念。Unicode是字符集,UTF-8、UTF-16是编码规则,具体概念如下:

字符集:为每一个「字符」分配了一个唯一的 ID或者编号(称为为码位 / 码点 Code Point)
编码规则:将「编号」转换为字节序列的规则

例如,‘中’ 的码点如下

在这里插入图片描述
其使用不同编码规则,进行编码的结果如下

在这里插入图片描述 

 


2. Unicode字符集
Java设计之初Unicode字符集中的字符个数还不到65536的一半,所以使用16位的char类型完全可以表示所有字符,但是,随着中、日、韩等其它字符的加入,导致Unicode字符集中的字符个数超过了65535,此时char类型已经无法表示Unicode字符集中的所有字符了。

我们先介绍一些必备的基础知识。

码点表示了一个字符的ID或者编号,在Unicode标准中,采用十六进制书写,并加上前缀U+,例如U+0041(转换为十进制即65),表示字母A的码点。

把Unicoee字符分为17个平面,每个平面包含不同种类的字符。

基本的多语言平面,码点范围U+0000~U+FFFF,表示了我们各个国家常用的字符,也是开始的char类型可以表示的字符。

其他平面(1到16号平面),码点范围U+10000~U+10FFFF,表示辅助字符,例如我们的不常用的繁体字等等,char类型无法直接表示这些字符,例如,char = '‘𝕆’ 会编译报错( 𝕆,一个数学符号,Unicdoe字符码点 U+1D546)

在这里插入图片描述
那么,char如何表示码点在U+10000~U+10FFFF之间的Unicode字符呢?

 

它借鉴了UTF-16编码规则。

UTF-16使用不同长度的编码表示所有Unicode字符。在基本的多语言平面中,使用16位表示一个字符,称为代码单元,而其他平面的辅助字符需要使用32位,也就是一对代码单元表示一个字符。

U+D800~U+DBFF表示第一个代码单元,U+DC00~U+DFFF表示第二个代码单元。

U+D800~U+DFFF,这一段码点称为替换区域,可以看出它属于基本的多语言平面(U+0000~U+FFFF)的范围,为了避免产生歧义或冲突,替换区域的码点没有没配给任何字符。

假设为替换区域码点分配了字符,就无法判断该码点是表示一个字符,还是辅助字符的第一个代码单元或第二个代码单元。

具体让我们看一下如何表示字符 ‘⑪’ (Unicdoe字符码点 U+1D546)?

第一个代码单元:D800到DBFF
1101 1000 0000 0000
1101 1011 1111 1111
110110XXXXXXXXXX 可以编码10位二进制数

第二个代码单元:DC00到DFFF
1101 1100 0000 0000
1101 1111 1111 1111
110111XXXXXXXXXX 可以编码10位二进制数

U+10000到U+10FFFF 可以看出转换成二进制树最多有21位,但是我们加起来最多可以编码20位二进制数,怎么办?

将范围偏移-10000,范围变成了U+0000到U+FFFFF,如此,就满足20位编码了。

⑪ U+1D546 偏移后U+D546

1101 0101 0100 0110

后十位“01 0100 0110"放入第二个代码单元110111XXXXXXXXXX:1101 1101 0100 0110,对应的十六进制数:DD46

前十位(不足十位首部补0)00001101 01 放入第一个代码单元110110XXXXXXXXXX:1101 1000 0011 0101,对应的十六进制数是:D835

因此,⑪,U+1D546使用两个代码单元表示:D835 DD46

我们在程序中如何存储码点在U+10000到U+10FFFF之间的字符呢?

直接存储字符字面量值或者转义序列\u,编译报错。很容易理解char类型16位正好只能存储一个代码单元,而该字符需要两个代码单元表示,无法用char类型直接表示该字符。

在这里插入图片描述

 

总结:现在,char类型用于描述一个代码单元。对于基本的多语言平面中的字符(码点范围U+0000到U+FFFF,不包含替换区域)可以使用一个代码单元表示,也就是一个char值。对于其他平面的字符(码点范围U+10000到U+10FFFF)可以使用两个代码单元表示,也就是两个char值。

严格来说,char类型可以表示使用一个代码单元表示的Unicode字符,char类型无法直接表示两个代码单元表示的字符。

怎么办,对于需要两个代码单元表示的字符就不能使用了吗?
不是的,我们可以把他们放在字符串类型中,字符串是由字符构成的,它把U+D800到U+DBFF之间的代码单元解读为字符的第一个代码单元,把U+DC00到U+DFFFF解读为字符的第二个代码单元,然后把两个代码单元解读为一个字符。它把U+0000到U+FFFF之间除去替换区域(U+D800到U +DFFF)的代码单元解读为一个字符。

String str = "\uD835\uDD46";

最后的建议,程序中最好不要使用char类型,除非你想处理代码单元。像操作Unicode字符,可以使用Java中的String类型。

 public static void main(String[] args) {

        // 字符串中放入需要两个码点表示的字符'𝕆'
        String  str = "𝕆A";

        // 获取索引为0的代码单元,而不是字符
        char ch0 = str.charAt(0);
        char ch1 = str.charAt(1);
        char ch2 = str.charAt(2);

        System.out.println(ch0);
        System.out.println(ch1);
        System.out.println(ch2);

    }

有些字符不能被正确的处理

在这里插入图片描述
————————————————
版权声明:本文为优快云博主「明月几时有666」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.youkuaiyun.com/gao_zhennan/article/details/124157890

 

<think>嗯,用户想了解Javachar类型的用法和特性。首先,我需要回忆一下Java的基本数据类型,特别是char的相关知识。根据之前学过的资料,记得char是用来存储单个字符的,占用2个字节,因为Java使用Unicode编码。 先确定char的基本定义,根据引用[1]和[2],char是16位无符号类型,存储的是Unicode字符。所以每个char变量可以表示一个Unicode基本多文种平面(BMP)的字符,也就是U+0000到U+FFFF之间的字符。但Unicode还有一些增补字符,需要两个char来表示,也就是代理对,这可能涉及引用[3]的内容。 接下来是取值范围,用户可能会关心char能存什么值。根据引用[2],char的范围是0到65535,所以可以存储像字母、数字、符号,包括中文字符。比如引用[4]提到的面试题,char能否存储中文汉字,答案是肯定的,因为中文字符在Unicode中属于BMP范围内。 然后是关于初始值的部分,Javachar的默认初始值是'\u0000',也就是空字符,不是空格,这点需要说明清楚。 内存占用方面,char占2个字节,这和C语言中的char不同,后者通常是1个字节。这点需要强调,避免混淆。 另外,处理增补字符的时候,可能需要用两个char或者直接使用String类,比如处理一些表情符号或者古文字,这时候需要提到代码点和代码单元的概念,这部分引用[3]可能有相关内容。 还要注意char的运算特性,比如自动转换为int类型,或者与byte、short的转换问题,可能需要强制类型转换,否则会编译错误。例如,char c = 65; 会得到'A',而进行算术运算时可能会提升为int。 用户可能的应用场景包括字符处理、加密算法中的位移操作,或者GUI开发中的字符显示。比如处理中文字符时,确保正确存储和显示。 潜在的问题可能有:为什么char是2字节?和C的区别,存储中文字符是否会有问题,如何正确处理增补字符,char的默认值是什么,以及类型转换的问题。这些问题应该在回答中覆盖,并生成相关的问题供用户进一步思考。 需要检查是否有遗漏的特性,比如转义字符的处理,或者char在switch语句中的使用。另外,是否提到字符字面量的表示方式,比如单引号,以及Unicode转义符的形式(如'\u0041')。 最后,确保引用的资料正确对应,比如引用[4]中的例子说明char可以存储中文,引用[1]和[2]说明内存占用和Unicode编码,引用[3]涉及增补字符的处理。 总结一下,回答的结构应该包括定义与用途、存储与编码、取值范围、默认值、内存占用、增补字符处理、类型转换、常见问题,然后生成相关问题。需要语言简洁,结构清晰,符合用户的要求,使用中文,正确使用LaTeX格式,如$2^{16}$,并引用对应的参考资料。</think>### Java char类型特性详解 #### 1. 定义与用途 - **基本定义**:charJava的16位无符号基本数据类型,用于存储单个Unicode字符,例如:$c = \text{'A'}$或$c = \text{'中'}$[^2]。 - **核心用途**:处理文本数据,如字符输入/输出、字符串操作等。 #### 2. 存储与编码 - **Unicode支持**:每个char存储一个Unicode基本字符(BMP范围:U+0000到U+FFFF),例如$\text{'©'}$(U+00A9)[^1]。 - **增补字符处理**:Unicode扩展字符(如𐐀,U+10400)需用两个char组成的代理对表示,例如: ```java String s = "\uD801\uDC00"; // 表示增补字符 ``` #### 3. 取值范围与默认值 - **数值范围**:$0$到$2^{16}-1$(即$0$到$65535$),对应十六进制$\text{0x0000}$到$\text{0xFFFF}$[^2]。 - **默认值**:未初始化时默认为$\text{'\u0000'}$(空字符,非空格)。 #### 4. 内存占用与性能 - **固定内存**:每个char占用2字节(与平台无关),例如: ```java char c = '汉'; // 存储中文汉字,占用2字节[^4] ``` - **优化场景**:大量字符处理时(如密码学运算),可直接操作char数值提升效率。 #### 5. 类型转换规则 - **隐式转换**:char可自动提升为int/long/float/double,例如: ```java int code = 'A'; // code=65 ``` - **强制转换**:从更大范围类型转换需显式声明,例如: ```java char c = (char) 0x4E2D; // c='中' ``` #### 6. 典型应用问题 - **中文存储**:单个char可直接存储中文字符(如$\text{'汉'}$),因汉字在Unicode BMP范围内[^4]。 - **特殊符号处理**:需注意转义字符(如$\text{'\n'}$)和Unicode转义写法(如$\text{'\u0041'}$)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值