Java进阶之深入理解Char

1 byte[]中的Unicode码

(1)Unicode码中的ASCII 码
在这里插入图片描述
(2)Unicode码中的非 ASCII 编码。简体中文汉字编码方式:GB2312编码等

Unicode码 26007 对应的字符为 斗
Unicode码 32599 对应的字符为 罗

(3)char[] 转换为byte[]
在这里插入图片描述
在这里插入图片描述

2 1字节=1byte=8bit=8位二进制;1int=4字节=32bit

bit又名比特、位,简称b,是计算机硬盘中的最小存储单位,是二进制中的一个数位“0”或数位“1”。
ASCII码值就是用一个字节,8位二进制表示一个字符或者符号

如:小写字母a的ASCII编码是97,不同进制表示如下
二进制:01100001(高四位0110,低四位0001)  
十进制:26 + 25 + 20 = 64 + 32 + 1 = 97

3 UTF-8 的编码规则

如何将中英文(人类认知的字符)–>Unicode(字符集)–>UTF-8编码(计算机存储)后,在计算机之间发送接收?

3.1 字符(人类认知)-> char (字符集)

方式1:手动套用模板
这个就是UTF-8规则编码,计算机指定了UTF8编码接收二进制并进行转移,当发现字节以0开头,表示这是一个标准ASCII字符,直接转义 ,当发现1110开头,就说明接下来的三个字节表示一个汉字,则取3个字节去掉模板后转义,UTF8编码规则如下:
在这里插入图片描述
1字节 0xxxxxxx
2字节 110xxxxx 10xxxxxx(GB2312)
3字节 1110xxxx 10xxxxxx 10xxxxxx(UTF8)
4字节 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
5字节 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
6字节 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
在这里插入图片描述
方式2:通过网站转码
(1)Unicode–>GB2312 Unicode–>GB2312

(2)Unicode–>UTF-8 Unicode–>UTF-8

3.2(2)-> byte (计算机存储):那么是如何换算呢?通过字节换算成网络流

(1)E6 => 1110 0110,因为java中byte是-128 ~ 127,高位是符号位;
(2)计算方式为:采用补码计算,取反后+1,去掉符号位,0001 1001 + 1 = 25 + 1 = 26;
(3)高位1位负数,所以E6对应-26,在通过字节传输给网络流,转成二进制;

4 举例子

4.1 字符(人类认知)-> char (字符集) :“斗”字

在这里插入图片描述
(1)字符为:斗;
(2)Unicode编码10进制是:26007,16进制是:0x6597,二进制是:1100 1011 0010 111;
(3)UTF-8使用3字节模板,得到:11100110 10010110 10010111,对应的UTF8编码:E69697(3字节)

4.2 -> byte (计算机存储):那么是如何换算呢?通过字节换算成网络流

在这里插入图片描述
(1)E6 => 1110 0110,因为java中byte是-128 ~ 127,高位是符号位;
计算方式为:采用补码计算,取反后+1,去掉符号位,0001 1001 + 1 = 25 + 1 = 26;
高位1位负数,所以E6对应-26,在通过字节传输给网络流,转成二进制;

(2)96 => 1001 0110
计算方式为:采用补码计算,取反后+1,去掉符号位,0110 1001 + 1 = 105 + 1 = 106;
高位1位负数,所以96对应-106,在通过字节传输给网络流,转成二进制;

(3)97 => 1110 0111
计算方式为:采用补码计算,取反后+1,去掉符号位,0110 1000 + 1 = 104 + 1 = 105;
高位1位负数,所以97对应-105,在通过字节传输给网络流,转成二进制;

5 Java中8种基本数据类型及其默认值

在这里插入图片描述

6 编码方式对比

6.1 ASCII 码和非ASCII 编码混乱的问题?

答:(1)ASCII 码:一共规定了128个字符的编码,比如空格SPACE是32(二进制00100000),大写的字母A是65(二进制01000001)
(2)非ASCII 编码:ASCII 码表示的128个字符以外的编码,世界上存在着多种编码方式,如:GB2312、GBK。但是同一个二进制数字可以被解释成不同的符号。因此,要想打开一个文本文件,就必须知道它的编码方式,否则用错误的编码解读,就会出现乱码。为什么电子邮件常常出现乱码?就是因为发信人和收信人使用的编码不一样。
(3)GB2312解决了ASCII不支持中文的问题;GBK是在GB2312基础上扩容后兼容GB2312的标准。

6.2 Unicode字符集和它的问题?

答:(1)Unicode为将世界上每种语言所有的符号都纳入其中,每一个符号都给予一个独一无二的二进制编码, 那么跨语言、跨平台的文本转换及处理的乱码问题就会消失。Unicode是一个很大的集合,现在的规模可以容纳100多万个符号。每个符号的编码都不一样,比如,U+0639表示阿拉伯字母Ain,U+0041表示英语的大写字母A,U+4E25表示汉字严。
(2)Unicode只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。比如,汉字严的Unicode是十六进制数4E25,转换成二进制数足足有15位(100111000100101),也就是说,这个符号的表示至少需要2个字节。表示其他更大的符号,需要3-4个字节,甚至更多。
(3)Unicode是一种编码方式,和ASCII是同一个概念,全部是英文的话,用Unicode编码比ASCII编码需要多一倍的存储空间。ASCII中英文字母只用一个字节表示就够了,而Unicode 统一规定,每个符号用2字节表示(固定长度),那么每个英文字母前都必然有1-2个字节是0,这对于存储来说是极大的浪费
(4)就有两个严重的问题,如何才能区别Unicode和ASCII?计算机怎么知道2个字节表示一个Unicode符号,而不是分别表示2个ASCII符号呢?

6.3 Unicode字符集和UTF-8的关系?

答:(1)在计算机内存中,统一使用Unicode编码,当需要保存到硬盘或者需要传输的时候,就转换为“可变长编码”的UTF-8编码
在这里插入图片描述
(2)UTF-8是什么?
答:UTF-8是Unicode的存储实现方式之一,提高性能的一种编码形式UTF-8最大的一个特点,就是它是一种变长的编码方式,可以使用1-4个字节表示一个符号,根据不同的符号而变化字节长度。其他还有,UTF-16使用2-4个字节表示一个符号和 UTF-32使用4个字节表示一个符号
(3)UTF-8与UTF-16的区别?
答:UTF-8最小的单位是1个字节,UTF-16最小的单位是2个字节;4位16进制,默认值为\u0000。也就是说,如果这个字符是a,a对应61,在UTF-8中它实际上和ASCII码相同, 也就是7个bit就可以表示,但在UTF-16中仍要2个字节的。

6.4 字符集与字符编码的区别?

(1)字符集就是字符的集合,包含了Unicode字符集、ASCII字符集、GBK/GB2312 简体字符集、ANSI字符集(西文字符+不同语言文字)等;
(2)编码方式可理解为定义在字符集上的映射(编码)规则查看上面的UTF-8的编码规则
(3)对于Unicode字符集,有Unicode、UTF-8、UTF-16、UTF-32等多种编码实现方式。但对于其他字符集,只有一种默认的编码方式,比如:ASCII,GBK,GB2312等,不仅仅代表字符集,同时也代表了默认的的编码方式。
在这里插入图片描述

6.5 学习链接

字符编码笔记:ASCII,Unicode和UTF-8

7 Java的char是两个字节,是怎么存Utf-8的字符的?

在这里插入图片描述
(1)char是什么?占几个字节?
答:char类型是原始类型,1byte=8bit ,16bit=1char=2byte,所以char永远占2个字节(2个字节表示一个char)。它的最小值为’\ u0000’(或0),最大值为’\ uffff’(或65,535(含))。二进制16 bit(216)–16进制(2424*2424)–24*2^4 24*24。

(2)char里面存的是什么?
答:Unicode字符集。Unicode为将世界上每种语言所有的符号都纳入其中,每一个符号都给予一个独一无二的二进制编码。Unicode通用字符集占2个字节,例如“庆”;
在这里插入图片描述
Unicode扩展字符集需要用两个char来表示,例如emoji表情 “👦👩” :

(3)字符集是什么?
答:字符集就是字符的集合,包含了Unicode字符集、ASCII字符集等

(4)UTF-8是什么?
答:存储实现方式可理解为定义在字符集上的映射(存储)规则。UTF-8最大的一个特点,就是它是一种变长的编码方式,可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度

(5)Unicode字符集和UTF-8的关系?
答:UTF-8是Unicode的编码实现方式之一

(6)Char是如何存UTF-8的字符的?
答:Char里面存的是Unicode字符集,在计算机储存中通过UTF-16这编码实现方式进行储存,不存UTF-8的字符。例如:字符‘中’的Unicode字符集是Ox4e2d,通过UTF16编码规则转换成字节存储(byte)。
在这里插入图片描述
(6)字节序标志是什么?
答:如果把字符换成字节,类似于字符‘中’,占1个char就可以了,也就是2个字节,同样是用UTF-16。其中 fe ff 是字节序的标志,不是代表的真正的内容, 而只是让读取这个数据的人知道字节序是什么。
在这里插入图片描述

(7)当运行代码时, 读入到内存里的字符(char)或字符串(String),实质上都是用char来表示的(String实质是char[])
答:

final class String {
      private final char[] value;
}

(8)Java String的length不一定是字符数?
答:String的length不一定是字符数,字符串长度不一定等于字符数,如:表情笑脸的字符串长度是2,字符数是1(1个表情)。
在这里插入图片描述

//  字符数是2(2个表情);字符串长度是4;所以字符串长度 不一定等于 字符数
val emoji  = "👦👩";
LogUtils.d(TAG, "emoji.length:${emoji.length} + emoji.bytes:${emoji.toByteArray().size} + emoji.char:${emoji.toCharArray().size}")
// 结果emoji.length:4 + emoji.bytes:8 + emoji.char:4

(9)Java9对字符串做了什么优化?
答:Java 9并没有改变字符串长度和字符数不一致的情况。但是对拉丁(Latin)字符的存储空间做了优化:UTF-16对于a, b, c等可以1个字节的还是需要两个字节来存,把char[]修改成byte[]来存,节省空间。

(10)为什么Java9需要优化呢?
答:按堆形式存储时,注意不影响按栈形式存储。char是2个字节,如果用来存一个字节的字符有点浪费,为了节约空间,Java 公司就改成了一个字节的byte来存储字符串。这样在存储一个字节的字符是就避免了浪费。

8 Java 语言中一个字符占几个字节?

答:想谈占几个字节,就要先把编码说清楚,同一个字符在不同的编码下可能占不同的字节。例如:"中"在GBK编码下占2字节,在UTF-16编码下也占2字节,在UTF-8编码下占3字节,在UTF-32编码下占4字节;"A"在UTF-8编码下占1字节,在UTF-16编码下占2字节,在UTF-32编码下占4字节。不同的字符在同一个编码下也可能占不同的字节,"中"在UTF-8编码下占3字节,而"A"在UTF-8编码下占1字节(因为UTF-8是变长编码)
Java 语言中一个字符占几个字节

// GBK+GBK2312:"中"占3字节;
// UTF-8:"A"占1字节,"中"占3字节;
// UTF-16:"A"占2字节,"中"占2字节;
// UTF-32:"A"和"中"都占4字节;

(1)Java中整数42,占几个字节?
答:具体看用byte,short,int,还是long来存它。用byte存就占一字节,用short存就占两字节,int 通常是四字节,long通常八字节。当然,如果用byte,受限于它有限的位数,有些数它是存不了的,比如256就无法放在一个byte里了。

(2)Java char能否存储一个汉字?
答:Java char是UTF-16编码方式,永远占2个字节。在UTF-16编码下一般的汉字占2字节,如"中"占2字节,所以可以储存一个汉字。特殊的中文生僻字,无法存储,会直接提示使用字符串,如:"𡃁"
在这里插入图片描述
(3)为什么String类型的"中"使用UTF-16编码时要用2个字节作为字节序,共占4个字节;而char类型的’中’用UTF-16编码时只占2个字节,不需要加字节序?
答:因为java的char的字节序是定义好的,char有明确的字节序,因此不需要用字节序标记。字符串不一样啊,字符串你不知道是谁用,所以要告诉它字节序

// "中"   utf-16
//        bytesUtf16.bytes(字节数):4 + bytesUtf16.char(字符数):1
//        bytesUtf16.toHexString:ffffffff
//        bytesUtf16.toHexString:fffffffe
//        bytesUtf16.toHexString:ffffff97
//        bytesUtf16.toHexString:65
// '中'   utf-16
//        chineseChar.byte:2
//        chineseChar.toHexString:4e
//        chineseChar.toHexString:2d

(4)Java中一个汉字字符串(String类型),占几个字节?
答:可能是2、3、4之一,因为getBytes()方法会根据当前默认的字符编码格式获取字节数组。gbk/gb2312占2个、utf-8占3个、utf-16占4个、unicode占4个,所以写代码时最好指定编码,建议通过 str.getBytes(“UTF-16”) 或 str.getBytes(“UTF-8”) 来指定编码方式,不带参数的getBytes方法通常是不建议使用的。如:“斗”.getBytes().length返回的是3,说明缺省编码是UTF-8。
在这里插入图片描述

9 其他问题解答

(1)utf16有些字符不是需要4个字节来存吗?那char两个字节怎么存得下呢?
答:如果有字符需要4个字节来存,用两个char存即可

(2)char类型转换?

答:输出c和100. 第二个输出多了类型转换。字符b在unicode中十进制对应98, 而(++n) 语句会先执行++n,所以为99,然后输出对应的字符, 即c。
在这里插入图片描述

(3)为什么char使用utf16存储?
答:Java char存utf8的话就有很多字符一个char存不下,存utf32的话又太浪费,所以折中选择了utf16

10 补充:课程视频的截图

在这里插入图片描述在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值