举个例子

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

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结果肯定一致的

小结

和例子1不一样,例子2是在生成class文件就已经是乱码的情况。这就是前面所说的,生成class乱码,但输出不一定是乱码。

总结

一句话:一定要保证java文件、编译、加载class文件、输出的编码格式一致。如果出现了乱码,可以从这几个阶段进行排查。

 

java编码详解的更多相关文章

  1. C++调用JAVA方法详解

    C++调用JAVA方法详解          博客分类: 本文主要参考http://tech.ccidnet.com/art/1081/20050413/237901_1.html 上的文章. C++ ...

  2. java 乱码详解_jsp中pageEncoding、charset=UTF -8"、request.setCharacterEncoding("UTF-8")

    http://blog.csdn.net/qinysong/article/details/1179480 java 乱码详解__jsp中pageEncoding.charset=UTF -8&quo ...

  3. Python2.7字符编码详解

    目录 Python2.7字符编码详解 声明 一. 字符编码基础 1.1 抽象字符清单(ACR) 1.2 已编码字符集(CCS) 1.3 字符编码格式(CEF) 1.3.1 ASCII(初创) 1.3. ...

  4. Java IO 详解

    Java IO 详解 初学java,一直搞不懂java里面的io关系,在网上找了很多大多都是给个结构图草草描述也看的不是很懂.而且没有结合到java7 的最新技术,所以自己来整理一下,有错的话请指正, ...

  5. java关键字(详解)

    目录 1. 基本类型 1) boolean 布尔型 2) byte 字节型 3) char 字符型 4) double 双精度 5) float 浮点 6) int 整型 7) long 长整型 8) ...

  6. 转1:Python字符编码详解

    Python27字符编码详解 声明 一 字符编码基础 1 抽象字符清单ACR 2 已编码字符集CCS 3 字符编码格式CEF 31 ASCII初创 311 ASCII 312 EASCII 32 MB ...

  7. 数据结构图文解析之:哈夫曼树与哈夫曼编码详解及C++模板实现

    0. 数据结构图文解析系列 数据结构系列文章 数据结构图文解析之:数组.单链表.双链表介绍及C++模板实现 数据结构图文解析之:栈的简介及C++模板实现 数据结构图文解析之:队列详解与C++模板实现 ...

  8. Java内部类详解

    Java内部类详解 说起内部类这个词,想必很多人都不陌生,但是又会觉得不熟悉.原因是平时编写代码时可能用到的场景不多,用得最多的是在有事件监听的情况下,并且即使用到也很少去总结内部类的用法.今天我们就 ...

  9. 黑马----JAVA迭代器详解

    JAVA迭代器详解 1.Interable.Iterator和ListIterator 1)迭代器生成接口Interable,用于生成一个具体迭代器 public interface Iterable ...

随机推荐

  1. 568. Maximum Vacation Days

    Problem statement:  LeetCode wants to give one of its best employees the option to travel among N ci ...

  2. javascript 中 with 的使用

    1)简要说明         with 语句可以方便地用来引用某个特定对象中已有的属性,但是不能用来给对象添加属性.要给对象创建新的属性,必须明确地引用该对象. 2)语法格式  with(object ...

  3. spring-boot整合dubbo:Spring-boot-dubbo-starter

    为什么要写这个小工具 如果你用过Spring-boot来提供dubbo服务,相信使用中有很多"不爽"的地方.既然使用spring boot,那么能用注解的地方绝不用xml配置,这才 ...

  4. Tomcat--安装与部署(一)

    一.Tomcat背景 自从JSP发布之后,推出了各式各样的JSP引擎.Apache Group在完成GNUJSP1.0的开发以后,开始考虑在SUN的JSWDK基础上开发一个可以直接提供Web服务的JS ...

  5. springboot(二):web综合开发

    上篇文章介绍了spring boot初级教程:spring boot(一):入门篇,方便大家快速入门.了解实践Spring boot特性:本篇文章接着上篇内容继续为大家介绍spring boot的其它 ...

  6. 关于String的问题

    String是在代码中非常常见的一种数据类型.它能直接像基本类型一样直接赋值(String str = "test"),也能像引用类型一样创建一个实例(String str = n ...

  7. 重新绑定ItemsSource先设置ItemsSource = null;的原因

    即报错信息为:在使用 ItemsSource 之前,项集合必须为空.   原因:Items和ItemSource,只能有一个生效,想用其中一个,另一个必须是空.   重新绑定ItemSource,虽然 ...

  8. Bash Scripting Learn Notes

    References: [1] http://www.tldp.org/LDP/Bash-Beginners-Guide/html/ 1. Executing programs from a scri ...

  9. SpringMVC 3.2集成Spring Security 3.2集成mybaties

    目录结构如下

  10. while循环 操作列表与字典

    1.在列表间移动元素 #!/usr/bin/env python #filename=list.py num1 = [1,3,5,7,9,11,13,15] num2 = [] while num1: ...