Java中char和String 的深入理解 - 字符编码
开篇
https://blog.csdn.net/weixin_37703598/article/details/80679376
我们并不是在写代码,我们只是将自己的思想通过代码表达出来!
1 将思维变现成为一行代码,是从抽象思维到具体代码的编码过程;继而计算机再将我们的代码再解码为计算机能处理的形式--2进制数字。
2 当计算机需要向你展示数据时它还需要将2进制数字参照一定的规则(码表)编码为人所能理解的格式。
如果不能清楚的理解编码和解码的原理和规则,我想作为程序猿的你是一定会善罢甘休的吧。哈哈,请随我的思路一起,让我们知其所以然吧!
我们这里只讨论狭义的计算机字符编码问题,以下论述都是基于此条件之下,才疏学浅,如有错误请同学们不吝赐教哦。
字符编码
1 总论
What/定义:编码是信息从一种形式或格式转换为另一种形式的过程,而解码是其逆过程。
Why/为什么需要编码:见开篇。
How/怎么编码:人们发明了很多码表,编码和解码实际上就是在查不同的码表(好像字典)的过程。
2 码表
2.1 祖宗:ASCII(American Standard Code for Information Interchange,美国标准信息交换代码),这是个单字节编码表,它能最多能表示256个字符(但实际上只用了7bit,128个。ISO8859-1使用8bit来表示,能表示256)。
(引用百度百科的图片,侵删)
2.2 Unicode
2 九十年代左右有两个组织分别做了两个码表要做统一,ISO的UCS 10646(Universal Character Set,UCS)和统一码联盟的Unicode。
但我们不需要两个不兼容的统一字符集,在1991年前后,他们终于联合起来共同维护一个标准了(他们还是各自发展,但字符集统一),从Unicode2.0开始,采用与ISO10646-1相同的字库和字码。两者目前兼容发展着。
3 UCS和Unicode使用最大32bit来表示字符,可以表示42亿个字符(4,294,967,296),目前只使用了1,114,112个码位,从0x0~0x10FFFF。
它们为了和不同的区域性字符集相互兼容,把其首256字符使用ISO8859-1所定义的字符,并把大量字符重复编到不同的字符码位置,从而使得旧有的纷繁复杂的编码方式得以和Unicode编码直接互相转换,而不会丢失任何信息。
4 UCS-4为4字节,它根据最高位为0的最高那1个字节,表示出2的7次方128个group,然后每个group根据此高字节分为256个plane,每个plane根据根据第3个字节分为256个row,每row有256个cell。group 0的plane 0 称为BMP(Basic Multilingual Plane)。
如果UCS-4的前2个字节全零(也就是用了plane 0),那么将UCS-4的BMP去掉前两个0字节就得到了UCS-2.
- 128group 256plane 256 row 256 cell
- 0000 0000,0000 0000,0000 0000,0000 0000
plane 0也有一个专用区:0xE000~0xF8FF,共6400个码位。它还有代理区(Surrogate)0xD800~0xDFFF(55296~57343),共2048个码位。代理区的目的是:用两个UTF-16字符表示BMP之外的字符。
238605-65535*2-6400-2048=99,089。这9万多个字符定义在plane 0(52080),1(3419),2(43253),14(337)上。有71,226个汉字,plane 2的43253都是汉字,plane0上定义了27973个汉字。
- Unicode Version 8.0 Released (2015.06.17)
目前的Unicode码表区段
0000..007F; Basic Latin
0080..00FF; Latin-1 Supplement
0100..017F; Latin Extended-A
0180..024F; Latin Extended-B
0250..02AF; IPA Extensions
02B0..02FF; Spacing Modifier Letters
0300..036F; Combining Diacritical Marks
0370..03FF; Greek
0400..04FF; Cyrillic
0530..058F; Armenian
0590..05FF; Hebrew
0600..06FF; Arabic
0700..074F; Syriac
0780..07BF; Thaana
0900..097F; Devanagari
0980..09FF; Bengali
0A00..0A7F; Gurmukhi
0A80..0AFF; Gujarati
0B00..0B7F; Oriya
0B80..0BFF; Tamil
0C00..0C7F; Telugu
0C80..0CFF; Kannada
0D00..0D7F; Malayalam
0D80..0DFF; Sinhala
0E00..0E7F; Thai
0E80..0EFF; Lao
0F00..0FFF; Tibetan
1000..109F; Myanmar
10A0..10FF; Georgian
1100..11FF; Hangul Jamo
1200..137F; Ethiopic
13A0..13FF; Cherokee
1400..167F; Unified Canadian Aboriginal Syllabics
1680..169F; Ogham
16A0..16FF; Runic
1780..17FF; Khmer
1800..18AF; Mongolian
1E00..1EFF; Latin Extended Additional
1F00..1FFF; Greek Extended
2000..206F; General Punctuation
2070..209F; Superscripts and Subscripts
20A0..20CF; Currency Symbols
20D0..20FF; Combining Marks for Symbols
2100..214F; Letterlike Symbols
2150..218F; Number Forms
2190..21FF; Arrows
2200..22FF; Mathematical Operators
2300..23FF; Miscellaneous Technical
2400..243F; Control Pictures
2440..245F; Optical Character Recognition
2460..24FF; Enclosed Alphanumerics
2500..257F; Box Drawing
2580..259F; Block Elements
25A0..25FF; Geometric Shapes
2600..26FF; Miscellaneous Symbols
2700..27BF; Dingbats
2800..28FF; Braille Patterns
2E80..2EFF; CJK Radicals Supplement
2F00..2FDF; Kangxi Radicals
2FF0..2FFF; Ideographic Description Characters
3000..303F; CJK Symbols and Punctuation
3040..309F; Hiragana(日文平假名)
30A0..30FF; Katakana(日文片假名)
3100..312F; Bopomofo
3130..318F; Hangul Compatibility Jamo
3190..319F; Kanbun
31A0..31BF; Bopomofo Extended
3200..32FF; Enclosed CJK Letters and Months
3300..33FF; CJK Compatibility
3400..4DB5; CJK Unified Ideographs Extension A
4E00..9FFF; CJK Unified Ideographs
A000..A48F; Yi Syllables
A490..A4CF; Yi Radicals
AC00..D7A3; Hangul Syllables
D800..DB7F; High Surrogates
DB80..DBFF; High Private Use Surrogates
DC00..DFFF; Low Surrogates
E000..F8FF; Private Use
F900..FAFF; CJK Compatibility Ideographs
FB00..FB4F; Alphabetic Presentation Forms
FB50..FDFF; Arabic Presentation Forms-A
FE20..FE2F; Combining Half Marks
FE30..FE4F; CJK Compatibility Forms
FE50..FE6F; Small Form Variants
FE70..FEFE; Arabic Presentation Forms-B
FEFF..FEFF; Specials
FF00..FFEF; Halfwidth and Fullwidth Forms
FFF0..FFFD; Specials
10300..1032F; Old Italic 10330..1034F; Gothic
10400..1044F; Deseret
1D000..1D0FF; Byzantine Musical Symbols
1D100..1D1FF; Musical Symbols
1D400..1D7FF; Mathematical Alphanumeric Symbols
20000..2A6D6; CJK Unified Ideographs Extension B
2F800..2FA1F; CJK Compatibility Ideographs Supplement
E0000..E007F; Tags
F0000..FFFFD; Private Use
100000..10FFFD; Private Use
最常用的CJK(Chinese Japanese Korean 中日韩文)区间段是4E00~9FFF,但9FA6~9FFF还是空的,所以实际有值得是4E00~9FA5,这也是大部分人判断中文所用的区段。但大家要知道,其实CJK大部分是描述的中文,日文和韩文还有相应的区间。上表中带有CJK的、平假名Hiragana、片假名Katakana、朝鲜文Hangul的都是中日韩文可能的字符区间:
CJK Unified Ideographs
只是常用的区间,全部CJK区间应该是:
2E80..2EFF(11904-12031): CJK Radicals Supplement
3000..303F(12288-12351): CJK Symbols and Punctuation
3040..309F(12352-12447): Hiragana(日文平假名)
30A0..30FF(12448-12543): Katakana(日文片假名)
3130..318F(12592-12687): Hangul Compatibility Jamo(朝鲜文兼容字母)
31F0..31FF(12784-12799): Katakana Phonetic Extensions(日文片假名语音括展)
3200..32FF(12800-13055): Enclosed CJK Letters and Months
3300..33FF(13056-13311): CJK Compatibility
3400..4DB5(13312-19893): CJK Unified Ideographs Extension A
4E00..9FFF(19968-40959): CJK Unified Ideographs
AC00..D7AF(44032-55215): Hangul Syllables(朝鲜文音节)
F900..FAFF(63744-64255): CJK Compatibility Ideographs
FE30..FE4F(65072-65103): CJK Compatibility Forms
20000..2A6D6(131072-173782): CJK Unified Ideographs Extension B
2F800..2FA1F(194560-195103): CJK Compatibility Ideographs Supplement

UCS-2编码(16进制) UTF-8 字节流(二进制)
0000 - 007F 0xxxxxxx
0080 - 07FF 110xxxxx 10xxxxxx
0800 - FFFF 1110xxxx 10xxxxxx 10xxxxxx
使用Unicode的推荐字节顺序标记方法BOM(Byte Order Mark)。
它的方法是:UCS中有个字符叫"ZERO WIDTH NO-BREAK SPACE",它编码为FE FF,还有个字符FF FE在UCS中不存在。
UCS规范建议我们在传输字节流最前,先传输字符FE FF表明字节流是Big-Endian;传输FF FE表明字节流是Little-Endian。
2.3 中国
GB GB2312 GBK 是国标以及其扩展码表。占用双字节。
BIG5是台湾/香港使用的繁体字符集。
GBK总体范围为:0x8140~0xFEFE,首字母在0x81~0xFE之间,尾字节在0x40~0xFE之间,剔除0x**7F一条线,总计23940个码位,收入21886个汉字(21003)和图形符号(883)。
JAVA
好了,我是Java程序员,我只为了理解《Tinking in java》中的一句话才搞了一天时间来研究这个问题的,好在还是有点成果!!
“java中有个基本类型char,它占用固定的2byte空间来表示字符,又因为java设计之初就采用了Unicode编码,所以char能表示所有字符包括中文。”
看到满世界这样的答案,我就不相信了!2字节最多只能标识65536个字符,它是怎么能囊括那么多字符的呢??仅所有汉字就不止6万吧!!!!
好了,不管你看没看完上边的文章,我告诉你结论就好!
结论
1. char
java中的char确实使用2Byte空间,它实际使用的是UCS-2 也就是plane 0,只能表述65536个字符,对于超出其范围的其它plane内容,请看下图:
一旦你使用了大于UCS-2的字符,那么编译器会直接报错!
其实也就是说char使用的是UTF-16格式。有个建议是尽量别用char类型,因为它会导致一些隐蔽的错误。比如,当你在用String时你定义了一个“虫”,你想当然的认为一个char就能盛放String中的一个字符(毕竟char是字符,而String就是描述的char数组),但是你会发现其实这个String的length()是2而不是1,因为它超出了UCS-2,String用两个char的位置(4字节)来表示了这个char,而String本该用一个char的位置来表示它才对。
2. String
首先,String能够支持的字符与你写代码时选择的编码方式有关,当你选择UTF编码时,你可以随便使用Unicode字符,用没脚”虫“当变量名都随你。使用GB*时,没脚虫”虫“不被支持(GBK收录的少一些吧或者这是日本字吧?)
其次,String在Java中是被定义为char数组来组织的,所以你定义的String最终要被转换成char来存放,但是,不要认为超出char的65536就不能存了,如果超出了它会用2个char来存放
在这里我想用两种方向来说1个String占用的空间
1. 在Java中实际使用的空间
这与使用的编码有关
UTF-8:2/4byte,其实就是1个char或者2个char;
GB*:2byte,就是1个char;
2. 如果对其编码,所需要的空间(String.getBytes())
UTF-8:1~4byte,ASCII用1Byte,汉字大部分用3Byte,其它字符参照上边UTF2.2的算法,超出UCS-2的部分比如那个“虫”就会是4Byte;
GB*:ASCII使用1Byte,其它中文2Byte;
3. 额外的部分---从java到class文件
无论.java文件你用GBK或者UTF-8来编码,编译器在将其编译为.class文件后,如果其中有字符串,会使用UTF-8来编码存储字节,占用1-4Byte。详细来说,就是在.class文件的常量池部分,这种字符串数据使用的数据结构是CONSTANT_Utf8_info,代表UTF-8编码的字符串。
最后吐槽一下!!!我打了3遍才把发布好这最后一段,一旦我打了那个少一腿的”虫“字,我后边的东西就被吃了,是保存到数据库时直接给我后边的忽视了吗???
Java中char和String 的深入理解 - 字符编码的更多相关文章
- Java中char和String的相互转换
转自:http://blog.csdn.net/yaokai_assultmaster/article/details/52082763 Java中char是一个基本类型,而String是一个引用类型 ...
- JAVA中char和String/值类型和引用类型的区别
import java.util.*; class test { public static void main(String[] args) { char a[] = {'b', 'a', 'c'} ...
- java中Integer 和String 之间的转换
java中Integer 和String 之间的转换 将数组转换成字符串:char[] array = {'a','b','c','d','e'};String str = new String(ar ...
- 【Java】Java中常用的String方法
本文转载于:java中常用的String方法 1 length()字符串的长度 String a = "Hello Word!"; System.out.println(a.len ...
- 关于java中char占几个字节,汉字占几个字节
我们平常说,java中char占2个字节,可又说汉字在不通的编码格式中所占的位数是不同的,比如gbk中汉字占2个字节,utf8中多数占3个字节,少数占4个.而所有汉字在java程序中我们都可以简单的用 ...
- Java中char转为16进制
Java中char转为16进制 char a = '0'; String hexStr = Integer.toHexString(a); System.out.println(hexStr);
- Java中关于static语句块的理解
Java中关于static语句块的理解 一.static块会在类被加载的时候执行且仅会被执行一次,一般用来初始化静态变量和调用静态方法. 实例一 public class A{ String name ...
- Java中常用的设计模式代码与理解
Java中常用的设计模式代码与理解 一.单例模式 1.饿汉式 (太饿了,类加载的时候就创建实例) /** * 饿汉式单例模式 */ public class HungrySingleInstance ...
- Java中如何将String转成Date
Java中如何将String转成Date 最近在开发Json数据反序列化为Java对象的时候发现spring mvc 和 Jackson 对Date类型对支持不是特别好,虽然在Java对象序列化为Js ...
随机推荐
- Shiro学习
Shiro学习资源 Shiro官网,http://shiro.apache.org/index.html 学习网站链接,http://blog.java1234.com/blog/articles/4 ...
- 关于Apahce服务器安装中遇到的问题
在这篇中,将记录一下安装Apache服务器所遇到的一些问题,并简单讲一些Apache和Tomcat的区别: 1>apache安装中遇到的问题: 1.1 Apache目前不再提供编译好的exe安装 ...
- ADO.NET学习笔记(1)
ADO.Net是.Net框架中为数据库的访问而封装的一个库.通过这个库我们可以简单便捷的访问数据库,并对数据库进行一些增删改查的操作,目前ADO.Net支持四种主流的数据库,分别是SQL.OLE DB ...
- JS模块化工具require.js教程(一):初识require.js
随着网站功能逐渐丰富,网页中的js也变得越来越复杂和臃肿,原有通过script标签来导入一个个的js文件这种方式已经不能满足现在互联网开发模式,我们需要团队协作.模块复用.单元测试等等一系列复杂的需求 ...
- 时序扩展的UML状态图的测试用例生成研究
一.基本信息 标题:时序扩展的UML状态图的测试用例生成研究 时间:2014 出版源:西南大学 领域分类:时序扩展:UML状态图:测试用例:需求规格说明:模型 二.研究背景 问题定义:时序扩展的UML ...
- 从git远程仓库Checkout项目到本地
一.登录coding 并且项目已创建好 已经是项目的组员 二.打开idea 1.弹出如下页面 复制远程项目上的SSH(URL)到下框URL 并且Test测试 成功就Clone即可 2.Clone ...
- 用python实现文件自动上传
一.简介 用python实现文件自动上传,主要源于在测试项目中想实现自动化上传文件功能,无须手工输入.比如从windows到Linux,或从Linux到windows,或从Linux到Linux. 主 ...
- (二)Javascript面向对象编程:构造函数的继承
Javascript面向对象编程:构造函数的继承 这个系列的第一部分,主要介绍了如何"封装"数据和方法,以及如何从原型对象生成实例. 今天要介绍的是,对象之间的"继承 ...
- 判断是否为AVL树
时间复杂度:O(n) // 判断是否为AVL树 public int isAVL(TreeNode node) { if (node == null) { return 0; } int left = ...
- 中间件 activeMQ Jms Java Demo
一.什么是ActiveMQ 百度解释: ActiveMQ 是Apache出品,最流行的,能力强劲的开源消息总线.ActiveMQ 是一个完全支持JMS1.1和J2EE 1.4规范的 JMS Provi ...