Java 中的字符编码与 String.getBytes()

发布于 2018-11-23  7.18k 次阅读


在任何编程语言中,存取和操作字符串都是一个常见的操作。这一切的前提,就要先规定存储和读取字符的规则,这就是字符串的编码。

一、字符串的编码

英文的编码就是ASCII,中文常见的编码有GBK和UTF-8编码。由于GBK和UTF-8编码的前128位就是ASCII码,所以英文和半角符号基本上没有乱码的情况。

二、Java中的编码与解码

默认情况下,JVM在加载Class文件的时候,会根据Class文件本身的编码来读取文件中的中文,读取到的中文在JVM中都会转成Unicode编码(不考虑JDK6与Windows XP)——在这种情况下,你自己写的代码中出现的中文应该总是可以正常显示的。

众所周知,char类型本身不含编码信息,只是纯数字,存储和操作时都是操作的这个数字。我们可以将一种编码理解为一个数组,需要显示字符的时候才拿着char对应的值去编码数组中取下标对应的符号显示出来。String类的内容就是存在一个字符(char)数组中的,下面是JDK8.0中String类的定义:

public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final char value[];
    ...
}

由于value数组是私有的,所以只有在调试模式下能看到它。除此以外,我们还可以使用String.getBytes()方法来取到它的值——但是,getBytes取到的未必是当前String中value数组中的值,还有可能是经过了编码转换后的值。

三、String.getBytes("encoding")

按照字面意思理解,这个函数应该是单纯的将String按照encoding编码分割为字节而已。但是,实际上它并不仅做了拆分,而且做了转换。困扰大多数初识Java的童鞋的问题应该就在转换这一步。

1. 如果encoding与字符串当前的编码一致:

那就直接分割为字节数组。

2. 如果encoding与字符串当前的编码不一致:

那就先按照原编码进行读取,然后按照编码映射规则将字符串转换为目标编码,然后分割为字节数组。

四、Java中对字符串进行转码

了解了以上内容,那么再处理乱码或者转码就变得胸有成竹了。不用管Java默认编码是什么、操作系统默认编码是什么,只需要getBytes一下即可:

String defaultString = "some 文本";
String gbkString = new String(defaultString.getBytes("GBK"), "GBK");//转成了GBK
String utf8String = new String(defaultString.getBytes("UTF-8"), "UTF-8");//转成了UTF-8
String utf8String = new String(gbkString.getBytes("UTF-8"), "UTF-8");//也可以转成UTF-8

如果你还是心存疑惑:转换的效果如何体现?那么可以试试下面的代码:

String x = "some 文本";
System.out.println("原始文本:"+x);
System.out.println("GBK编码:\n字节流:"+Arrays.toString(x.getBytes("GBK")));
System.out.println("长度:"+x.getBytes("GBK").length);
System.out.println("GBK解码:"+new String(x.getBytes("GBK"), "GBK"));
System.out.println("UTF-8解码:"+new String(x.getBytes("GBK"), "UTF-8"));
System.out.println("UTF-8编码:\n字节流:"+Arrays.toString(x.getBytes("UTF-8")));
System.out.println("长度:"+x.getBytes("UTF-8").length);
System.out.println("UTF-8解码:"+new String(x.getBytes("UTF-8"), "UTF-8"));
System.out.println("GBK解码:"+new String(x.getBytes("UTF-8"), "GBK"));

如果可以理解以上输出内容,那么恭喜,你已经掌握了Java中的编码:)

特别鸣谢:张强、刘舰阳、白高阳、张峰的帮助与提点。