举个例子

我们在开发过程中,特别是多种编码格式并存的情况下,很容易遇到乱码问题。 假如有一个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. Linux下memcache的安装和启动测试

    memcache是一套分布式的高速缓存系统,MemCache的工作流程如下:先检查客户端的请求数据是否在memcached中,如有,直接把请求数据返回,不再对数据库进行任何操作:如果请求的数据不在me ...

  2. j2ee分布式架构 dubbo + springmvc + mybatis + ehcache + redis 分布式架构

    介绍 <modules>        <!-- jeesz 工具jar -->        <module>jeesz-utils</module> ...

  3. .Net Core 连输入中文都变坑了...

    前不久Core诞生时候,那个时候我也在项目上没时间去尝那青涩的味道.今天刚刚装上2017就等不及的试了一下. 先创建了一个控制台的应用程序,然后在Main()方法中写了几句话,就等不及的Ctrl+F5 ...

  4. 使用javascript生成当前博文地址的二维码图片

    前面的话 在电脑端发现一篇好的博文,想在手机上访问.这时,就必须打开手机浏览器输入长长的URL地址才行,非常不方便.如果在博客标题的后面跟一张小的图片,点击该图片后,出现一张二维码的大图,然后再通过手 ...

  5. Android官方架构组件介绍之LifeCycle

    Google 2017 I/O开发者大会于近日召开,在开发者大会上谷歌除了发布了Android O等一些新产品之外,也对Android代码的架构做出了一个官方的回应. Google 2017 I/O开 ...

  6. (Unsupported class version number [52.0] (maximum 51.0, Java 1.7))

    遇到类似问题,主要原因是proguard版本只支持到java7,而我使用的是java8. 解决方法是下载最新proguard(支持java 8的版本),然后将下载的文件解压,将libs下jar与and ...

  7. convertView的疑问(软件管理器)

    package com.hixin.appexplorer; import java.util.List; import android.app.Activity; import android.co ...

  8. itmacy_我的博客

    开通博客的第一天,并不希望自己以后像写流水账一样来写自己的博客,而是希望每一篇博客,无论是转载还是原创,都是经过深思熟虑,并且有意义的...

  9. 解决相关css基础问题

    //html代码 <div class="operateWays"> <label> <input type="radio" na ...

  10. 【JAVAEE学习笔记】hibernate03:多表操作详解、级联、关系维护和练习:添加联系人

    一.一对多|多对一 1.关系表达 表中的表达 实体中的表达 orm元数据中表达 一对多 <!-- 集合,一对多关系,在配置文件中配置 --> <!-- name属性:集合属性名 co ...