Java 字符集 编码
Java 字符集 编码
Java默认的字符集是Unicode(占两个字节byte,一个字节=8比特位bit)
详解:
字符集 编码
Unicode 是「字符集」;UTF-8 是「编码规则」(是使用最广的一种 Unicode 的实现方式)
字符集:为每一个字符分配一个唯一的ID(码位)
编码规则:将码位转换为字节序列的规则(用什么方式存储)
|
英文/字节 |
中文/字节 |
Utf-8(变长) |
1 |
3 |
Utf-16 |
2 |
3-4 |
GBK |
1 |
2 |
ISO8859-1 |
1 |
1 |
Unicode |
2 |
2(标点也是) |
ASCII |
1 |
2 |
Java的处理方法:
编码问题存在两个方面:JVM之内和JVM之外。
1.编译器把Java文件编译后形成class
这里Java文件的编码可能有多种多样(可以为utf-8(常用)),但Java编译器会自动将这些编码按照Java文件的编码格式正确读取后产生class文件,这里的class文件编码是Unicode编码(具体说是UTF-16编码)。也就是说完成了从UTF-8编码的文件转成与平台无关的.class文件了,把UTF-8编码方式转成了Unicode。一旦编译成.class文件,就不用在乎关于我们程序源码的什么UTF-8编码了
因此,在Java代码中定义一个字符串String s="汉字";
不管在编译前java文件使用何种编码,在编译后成class后,他们都是一样的----Unicode编码表示。
2.JVM中的编码
在JVM内部,统一使用Unicode表示,当着字符从JVM内部移动到外部时(即保存为文件系统中的一个文件内容时),就进行了编码转换,使用了具体的编码方案。因此也可以说,所有的编码转换只发生在边界的地方,也就是各种输入/输出流的起作用的地方。
JVM加载class文件读取时候使用Unicode编码方式正确读取class文件,那么原来定义的String s="汉字";在内存中的表现形式是Unicode编码。
问题
在java中,一个字符等于多少字节?
或者更详细的问:在java中,一个英文字符等于多少字节?一个中文字符等于多少字节?
Java采用unicode来表示字符,java中的一个char是2个字节,一个中文或英文字符的unicode编码都占2个字节,但如果采用其他编码方式,一个字符占用的字节数则各不相同。
代码验证如下:
public static void main(String[] args) { String str = "测"; char x = '测'; byte[] byteStr = str.getBytes(); byte[] byteChar = charToByte(x); System.out.println("byteStr :" + byteStr.length); // byteStr :3 System.out.println("byteChar:" + byteChar.length); // byteChar:2 } // 通过移位获取char类型的byte数组 public static byte[] charToByte(char c) { byte[] b = new byte[2]; b[0] = (byte) ((c & 0xFF00) >> 8); b[1] = (byte) (c & 0xFF); return b; }
获取系统编码
System.out.println("系统默认编码:" + System.getProperty("file.encoding")); //查询结果UTF-8 System.out.println("系统默认字符编码:" + Charset.defaultCharset()); //查询结果UTF-8 System.out.println("系统默认语言:" + System.getProperty("user.language")); //查询结果zh
getBytes()方法详解
另外解释一下上边使用的getBytes()方法
在Java中,String的getBytes()方法是得到一个操作系统默认的编码格式的字节数组。这表示在不同的操作系统下,返回的东西不一样!
1.str.getBytes(); 如果括号中不写charset,则采用的是Sytem.getProperty("file.encoding"),即当前文件的编码方式,
2.str.getBytes("charset");//指定charset,即将底层存储的Unicode码解析为charset编码格式的字节数组方式
3.String str=new String(str.getBytes("utf-8"),"gbk")); //将已经解析出来的字节数据转化为gbk编码格式的字符串,在内存中即为gbk格式的字节数组转为Unicode去交互传递
引申
问:
"a".getBytes("Unicode").length // 结果为 4
上边已经说过Unicode一个字符占两个字节,这里为什么是4字节不是2字节?
为什么Unicode 4个字节
使用for循环遍历得到的byte数组(还是使用字符 a ):
-2 -1 0 97
发现前边多了一个 -2 -1 ,这其实是一个字节的BOM标志。
UNICODE 是一种字符集,在 Java 中直接使用 Unicode 转码时会按照 UTF-16LE 的方式拆分,由于 UTF-16 分为 UTF-16LE 和 UTF-16BE,也就是小端序和大端序,因此在网络传过程中,无法判断是 LE 还是 BE 序的,因此需要加上一个额外的字节序 BOM 头。BOM 头的字符是一个特殊的字符,其 Unicode 编码为 U+FEFF,字符名为“ZERO WIDTH NON-BREAKING SPACE”,根据 RFC2781 3.2 节规定,开头两个字节为 FE FF 的称为Big-Endian,开头为 FF FE 的称为 Little-Endian。
关于utf-16的解释:utf-16的方式包含2种字节序,Big Endian字节序和Little Endian字节序:
UTF-16 Big Endian:FEFF (没有含义在UCS-2中),其中FEFF为标示码
UTF-16 Little Endian:FFFE (没有含义在UCS-2中),java默认选择Little Endian字节序
因此,你直接使用 Unicode 转换字节的话,也就是按 UTF-16LE 方式进行解码,会额外地加上 BOM 的两个字节 FF FE。
解决办法:
可以使用UnicodeBigUnmarked编码
"a".getBytes("UnicodeBigUnmarked").length // 结果为2
参考:
http://bbs.itheima.com/thread-101106-1-1.html
https://blog.csdn.net/lcfeng1982/article/details/6830584
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)