Java字符编码

Java中的字符编码

  • 编译时,可以通过javac命令的-encoding选项,指定源代码文件的编码
  • 运行时,可以通过java命令的-D选项,设置file.encoding属性,这个属性会作为reader、writer、String.getBytes()等操作的默认编码
  • class文件的编码是UTF-8
  • JVM运行时,使用UTF-16编码
    • UTF-16是双字节编码,Java的char也是双字节的
    • UTF-16并不是固定占用2个字节,根据字符在unicode字符集中的位置,可能占用2个字节,也可能占用4个字节

字符集、字符编码基础

  • 字符集
    • 字符集顾名思义就是字符的集合,字符集定义了Code Point(中文名是:码位,它是一个数值)和字符之间的映射关系。比如,ASCII是一个字符集,字母a是ASCII字符集中的一个字符,字母a的Code Point是97。字符集中有多少个Code Point是由字符集规定的。比如unicode字符集是使用4个字节的数值来表示字符,因此unicode字符集有2的32次方个Code Point,但是并非所有的Code Point都被使用了。
  • 字符编码
    • 字符编码是字符集的一个实现。比如UTF-8UTF-16UTF-32都是unicode字符集的实现
    • 字符编码是一套规则,通过这套规则,可以将计算机中的字节序列匹配到字符集的字符上

String 和 字节序列

  • String是UTF-16编码的字符串
  • String的getBytes()方法 用于将String按照指定的字符集进行编码(encode)
    • encode - 将字符序列 转换成 某种编码的字节序列
  • new String() 用于将某种编码的字节序列进行解码(decode)
    • decode - 将某种编码的字节序列 转换成 字符序列

Python中的字符编码

本文是针对Python2x的

  • Python源代码文件的编码,通过#coding: utf8之类的注释来指定
  • Python中获取默认的字符编码:
>>> import sys
>>> sys.getdefaultencoding()
'ascii'  
  • Python中设置默认的字符编码:
>>> import sys
>>> reload(sys)
<module 'sys' (built-in)>  
>>> sys.setdefaultencoding("UTF-8")
>>> sys.getdefaultencoding()
'UTF-8'  


需要特别注意的是,当混用str和unicode的时候,Python会尝试用默认的编码对str进行解码:
1111

  • Python运行时,使用两个字节存储unicode(可以在编译Python时,可以指定使用UCS-2字符集,还是UCS-4字符集)
  • pyc文件:编译Python源代码会得到一个PyCodeObject对象,使用marshal(Python的一个序列化库)将PyCodeObject对象进行序列化,并保存到磁盘,就会得到一个pyc文件。可将其类比为Java的class文件。pyc文件是ascii编码的

例1

// filename: Main.java

public class Main {  
    public static void main(String[] args) throws Exception {
        // javac会使用-encoding选项指定的或操作系统默认的字符编码对源代码进行解码
        String string = "汉";

        System.out.println("Internal:");
        for (int ind=0; ind<string.length(); ++ind)
            System.out.print(String.format("\t%x", (int)string.charAt(ind)));

        System.out.print("\nUTF-8:\n\t");
        byte[] bytes = string.getBytes("UTF-8");
        for (byte b: bytes)
            System.out.print(String.format("%1$x", b));

        System.out.print("\nGBK:\n\t");
        bytes = string.getBytes("GBK");
        for (byte b: bytes)
            System.out.print(String.format("%1$x", b));
    }
}


IDEA的右下角可以指定源代码文件的字符编码:
2222 将上面的源代码文件的编码设置为UTF-8。
因为windows的默认编码是GBK,所以执行javac Main.java,编译源代码文件时,会报错:
3333 可以通过-encoding命令行选项来指定源代码文件的编码:javac -encoding UTF-8 Main.java
执行编译后得到的class:
java Main
输出如下:
4444 可见:unicode字符“汉”在JVM内部被存储为6C49,对应的UTF-8字节序列是E6 B1 89,对应的GBK字节序列是BA BA。


例2

public class Main {  
    public static void main(String[] args) throws Exception {
        byte[] bytes = new byte[]{-26, -79, -119};
        System.out.println("file.encoding=" + System.getProperty("file.encoding"));
        System.out.println(new String(bytes));
    }
}


编译:

javac Main.java  


执行:

java Main  


输出如下: 5555 使用GBK编码给UTF-8字节序列解码的时候,会出乱码。可以通过-Dfile.encoding=xxx的方式指定默认编码:
java -Dfile.encoding=UTF-8 Main
输出如下:
6666

感谢浏览tim chow的作品!

如果您喜欢,可以分享到: 更多

如果您有任何疑问或想要与tim chow进行交流

可点此给tim chow发信

如有问题,也可在下面留言: