java编码详解

简介:

举个例子

我们在开发过程中,特别是多种编码格式并存的情况下,很容易遇到乱码问题。 假如有一个GBK编码java文件,然后再使用-Dfile.encoding=GBK参数,写入的文件中哪些是乱码呢。那如果使用UFT-8编码的java文件呢。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public  class  Main {
     static  String content =  "中文" ;
 
     public  static  void  main(String[] args)  throws  IOException {
         OutputStreamWriter gbkWriter = new  OutputStreamWriter( new  FileOutputStream( "GBK-FILE" ), "GBK" );
 
        // 情况1、2、5的结果肯定是一致的
         gbkWriter.write(content+ "\n" );  //(1)
         gbkWriter.write( new  String(content.getBytes( "GBK" ), "GBK" )+ "\n" );              // (2)
         gbkWriter.write( new  String(content.getBytes( "GBK" ),  "UTF-8" )+ "\n" );           // (3)
         gbkWriter.write( new  String(content.getBytes( "UTF-8" ), "GBK" )+ "\n" );             // (4)
         gbkWriter.write( new  String(content.getBytes( "UTF-8" ),  "UTF-8" )+ "\n" );    // (5)
 
         gbkWriter.flush();
         gbkWriter.close();
 
     }
}

  

java编译到输出

其实用一张图就可以清晰的概括出从java文件编译到输出的过程  主要有3个地方的编码转换:

编译过程

上图①所示的位置,其实就是

javac -encoding xxx

的时候控制,如果你没有显示的指定编码,那么会根据当前操作系统的默认编码格式进行编译,一般windows是gbk,linux是UTF-8。如果这里编码指定错了,那么你的代码很有可能出现中文乱码问题,注意是很有可能,而不是绝对。原因后面会说到。编译出来的class文件统一都是UTF-8格式

运行加载

当class文件加载的jvm的时候,也会进行字符串编码转换,和前面一样,会使用操作系统默认的编码格式,这里的编码不是指class文件的编码,而是指java文件的编码格式,类似于指定java文件是什么编码格式编译为class文件的。就是jvm参数:

java -Dfile.encoding=xxx

在java运行过程中,字符串在内存中则是使用Unicode(UTF-16)进行存储的。而UTF-8转换为UTF-16是很简单的过程。当我们标用String.getBytes()时候,则是把内存中的unicode转换对应的字节数组。(如果没有指定,则使用操作系统默认的编码格式)。可以看出,把一个字符串从编译到内存,其实是经历的过程为:

编译文件编码->加载jvm编码->unicode

输出

输出的编码则是在代码中指定的。例如: OutputStreamWriter gbkWriter =new OutputStreamWriter(new FileOutputStream("GBK-FILE"),"GBK");

例子解析

如果理解上面的,我们再看看文章一开始的例子。举几个例子做说明,其他的情况也就逐类旁通。

例子1

  • java文件编码:GBK,

  • javac -encoding GBK

  • java -Dfile.encoding=GBK 那么使用GBK编码查看输出文件

  • (1)正常

  • (2)正常

  • (3)乱码

  • (4)乱码

  • (5)正常

情况(1)

情况1是比较好理解的,因为java文件编码、编译、加载都是使用GBK,加载到内存中Unicode肯定也是正常的,那么打印出来也是正常的。

情况(2)和情况(5)

在情况1的前提下(即加载到内存中是正常的),在jvm中使用GBK解码在编码肯定是正常的。

情况(3)和情况(4)

在情况1的前提下,使用不同的解码和编码,肯定是乱码

特殊情况

当我们使用UTF-8的格式打开文件的时候,情况(4)是正常的,其余都是乱码。其实是因为先使用unicode进行转换为UTF-8格式的Byte数组,生成的字符串虽然乱码和写文件的格式都是GBK,相当于原封不动的UTF-8格式的byte数组写到文件中,所以就会出现这个情况

小节

这个例子就是直至加载到内存都是正常的情况下,在jvm内进行编码和解码导致乱码的情况

例子2

  • java文件编码:UTF-8,

  • javac -encoding GBK

  • java -Dfile.encoding=UTF-8

那么使用GBK编码查看输出文件

  • (1)乱码

  • (2)乱码

  • (3)正常

  • (4)乱码

  • (5)乱码

情况(1)

情况1是乱码,说明字符串加载到内存中就已经是乱码了。因为UFT-8格式使用GBK进行编码,在生成class文件就已经是乱码了。

情况(3)

情况3为什么又是正常的呢,其实这是误打误撞类型。个人理解的造成这个情况的原因有:

  1. java文件的编码正好和jvm加载文件编码格式是一样的

  2. javac过程,相当于一个UTF-8->GBK格式转换,而content.getBytes("GBK"), "UTF-8")又相当于GBK->UTF-8的转换,两次转换正好相互抵消。

使用UTF-8编码查看输出文件

  • (1)正常

  • (2)正常

  • (3)乱码

  • (4)乱码

  • (5)正常

为什么是使用UTF-8打开情况1不是乱码了呢,其实和上面误打误撞,只不过之前发生在内存中的GBK->UTF-8换为我们在打开文件的时候进行的编码转换,情况1、2、5结果肯定一致的


本文转自 bxst 51CTO博客,原文链接:http://blog.51cto.com/13013670/1944050


相关文章
|
3月前
|
存储 Java Android开发
IO流:java中解码和编码出现乱码说明及代码实现
IO流:java中解码和编码出现乱码说明及代码实现
|
6月前
|
存储 Java
使用Java进行Base64编码的示例
使用Java进行Base64编码的示例
67 1
|
5月前
|
Kubernetes 数据可视化 搜索推荐
学习Java 8 Stream,提升编码能力!
学习Java 8 Stream,提升编码能力!
|
6天前
|
Java API
编码的奇迹:Java 21引入有序集合,数据结构再进化
编码的奇迹:Java 21引入有序集合,数据结构再进化
13 0
|
6天前
|
Java Shell
Java 21颠覆传统:未命名类与实例Main方法的编码变革
Java 21颠覆传统:未命名类与实例Main方法的编码变革
10 0
|
4月前
|
数据采集 Java 数据挖掘
java获取输入的地点的经纬度和编码等信息
java获取输入的地点的经纬度和编码等信息
21 0
|
6月前
|
IDE Java 测试技术
【Java开发编码的工作效率问题工作经验之谈】
【Java开发编码的工作效率问题工作经验之谈】
|
8月前
|
Java
第二季:10.死锁编码及定位分析【Java面试题】
第二季:10.死锁编码及定位分析【Java面试题】
46 0
|
8月前
|
Java 容器
第二季:4我们知道ArrayList是线程不安全,请编码写一个不安全的案例并给出解决方案。【Java面试题】
第二季:4我们知道ArrayList是线程不安全,请编码写一个不安全的案例并给出解决方案。【Java面试题】
39 0
|
9月前
|
Java 测试技术 Docker
docker export,import后无法运行,如java命令找不到,运行后容器内编码有问题
在进行docker export导出镜像,然后import后运行,发现要么提示无执行命令,要么找不到执行程序,这都是因为在export后都失效了,所以我们需要在当前Dockerfile里重新声明一下,然后我这还发现容器内中文乱码,所以编码也需设置一下,具体配置如下:
317 2