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中的一个char2个字节,一个中文或英文字符的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,StringgetBytes()方法是得到一个操作系统默认的编码格式的字节数组。这表示在不同的操作系统下,返回的东西不一样!

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 EndianFEFF (没有含义在UCS-2),其中FEFF为标示码
UTF-16 Little EndianFFFE (没有含义在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 

猜你喜欢

转载自www.cnblogs.com/scChen/p/12508571.html
今日推荐