首先说一下,乱码的英语是mojibake!
java编程中,关于编码有三个地方需要弄清楚,java源文件、class文件、虚拟机
java源文件
源文件可以是任何编码的文件,这取决于保存形式。所以编译时需要指明源文件的编码方式,比如 javac -encoding utf8 HelloWorld.java,如果不指定,默认是操作系统编码。
本来java读取文件跟文件编码无关,但是,在javac编译过程中,存在将二进制解码为字符,然后再将字符编码为二进制的过程,所以需要指定源文件的编码方式。
class文件
无论源文件的编码格式是什么,class文件都是modified UTF-8,modified utf-8是java对utf-8作了修改的版本,正因为class文件的编码方式的统一,所以class文件才会跨平台
modified utf-8与传统utf-8的的异同:在基本平面内也就是字符u+0000-u+FFFF范围内,都是一样的存储方案。在增补平面内,modified utf-8是用6个字节表示一个字符,utf-8,使用4个字节表示一个字符。这是因为java发布的时候,unicode的基本平面,还远远没有满,modified utf-8将增补平面内的字符,分解为两个代码点比如0xyyy,0xzzz,每个代码点使用3个字节表示,所以就是一共6个字节。
java虚拟机编码
java虚拟机的编码是utf-16,双字节表示一个字符,请切记java虚拟机中的编码方式是utf-16
java生命周期
java源文件---->class 文件------->jvm(输入流、输出流)---------->控制台
上述任何一个阶段,都会存在编码解码,只要存在编码解码就会存在乱码的问题。
问题:
byte[] arr = "x".getBytes();
这句程序的意思是,返回字符串x在操作系统默认编码方案下的字节数组,通常情况下,中文操作系统是gbk,英文操作系统是iso8859-1,可以通过-Dfile.encoding=xx,来影响操作系统的默认编码(jvm认为的操作系统编码),通过查看源码会发现,这个设置最终会影响Charset.defaultCharset()
关于-Dfile.encoding与charset.defaultcharset(),可以参考我的另一篇博文-Dfile.encoding与Charset.defaultCharset()关系