java编码详解
举个例子
我们在开发过程中,特别是多种编码格式并存的情况下,很容易遇到乱码问题。 假如有一个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为什么又是正常的呢,其实这是误打误撞类型。个人理解的造成这个情况的原因有:
- java文件的编码正好和jvm加载文件编码格式是一样的
- 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编码详解的更多相关文章
- C++调用JAVA方法详解
C++调用JAVA方法详解 博客分类: 本文主要参考http://tech.ccidnet.com/art/1081/20050413/237901_1.html 上的文章. C++ ...
- 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 ...
- Python2.7字符编码详解
目录 Python2.7字符编码详解 声明 一. 字符编码基础 1.1 抽象字符清单(ACR) 1.2 已编码字符集(CCS) 1.3 字符编码格式(CEF) 1.3.1 ASCII(初创) 1.3. ...
- Java IO 详解
Java IO 详解 初学java,一直搞不懂java里面的io关系,在网上找了很多大多都是给个结构图草草描述也看的不是很懂.而且没有结合到java7 的最新技术,所以自己来整理一下,有错的话请指正, ...
- java关键字(详解)
目录 1. 基本类型 1) boolean 布尔型 2) byte 字节型 3) char 字符型 4) double 双精度 5) float 浮点 6) int 整型 7) long 长整型 8) ...
- 转1:Python字符编码详解
Python27字符编码详解 声明 一 字符编码基础 1 抽象字符清单ACR 2 已编码字符集CCS 3 字符编码格式CEF 31 ASCII初创 311 ASCII 312 EASCII 32 MB ...
- 数据结构图文解析之:哈夫曼树与哈夫曼编码详解及C++模板实现
0. 数据结构图文解析系列 数据结构系列文章 数据结构图文解析之:数组.单链表.双链表介绍及C++模板实现 数据结构图文解析之:栈的简介及C++模板实现 数据结构图文解析之:队列详解与C++模板实现 ...
- Java内部类详解
Java内部类详解 说起内部类这个词,想必很多人都不陌生,但是又会觉得不熟悉.原因是平时编写代码时可能用到的场景不多,用得最多的是在有事件监听的情况下,并且即使用到也很少去总结内部类的用法.今天我们就 ...
- 黑马----JAVA迭代器详解
JAVA迭代器详解 1.Interable.Iterator和ListIterator 1)迭代器生成接口Interable,用于生成一个具体迭代器 public interface Iterable ...
随机推荐
- 智能指针剖析(上)std::auto_ptr与boost::scoped_ptr
1. 引入 C++语言中的动态内存分配没有自动回收机制,动态开辟的空间需要用户自己来维护,在出函数作用域或者程序正常退出前必须释放掉. 即程序员每次 new 出来的内存都要手动 delete,否则会造 ...
- [刷题]算法竞赛入门经典(第2版) 5-16/UVa212 - Use of Hospital Facilities
题意:模拟患者做手术. 其条件为:医院有Nop个手术室.准备手术室要Mop分钟,另有Nre个恢复用的床.准备每张床要Mre分钟,早上Ts点整医院开张,从手术室手术完毕转移到回复床要Mtr分钟.现在医院 ...
- 关于php调用.net的web service 踩过的坑
从前一阵开始,公司要和对方做web service对接.由于对方使用.net语言,而我方使用php.本来经理是要求我们也用.net写web service的服务端.而我上学时学的.net全忘了... ...
- MySQL的SELECT ...for update
最近的项目中,因为涉及到Mysql数据中乐观锁和悲观锁的使用,所以结合项目和网上的知识点对乐观锁和悲观锁的知识进行总结. 悲观锁介绍 悲观锁是对数据被的修改持悲观态度(认为数据在被修改的时候一定会存在 ...
- 实现ThreadFactory接口生成自定义的线程给Fork/Join框架
Fork/Join框架是Java7中最有趣的特征之一.它是Executor和ExecutorService接口的一个实现,允许你执行Callable和Runnable任务而不用管理这些执行线程.这个执 ...
- 基于spark和sparkstreaming的word2vec
概述 Word2vec是一款由谷歌发布开源的自然语言处理算法,其目的是把words转换成vectors,从而可以用数学的方法来分析words之间的关系.Spark其该算法进行了封装,并在mllib中实 ...
- linux通配符与正则表达式
通配符 * 任意字符,可重复多次 ? 任意字符,重复一次 [] 代表一个字符 举例: [a,b,c] 表示abc中任意一个 通配符的作用是用来匹配文件名的 正则表达式 正则表达式 ...
- .Net程序员学用Oracle系列(29):PLSQL 之批量应用和系统包
1.批量数据操作 1.1.批量生成数据 1.2.批量插入数据 2.批量生成脚本 3.生成数据字典 4.常见系统包 4.1.DBMS_OUTPUT 4.2.DBMS_RANDOM 4.3.其它系统包及常 ...
- WannaflyUnion每日一题
---恢复内容开始--- 1. http://www.spoj.com/problems/KAOS/ 题意:给定n个字符串,统计字符串(s1, s2)的对数,使得s1的字典序比s2的字典序要大,s1反 ...
- .Net程序员学用Oracle系列(30):零碎补充、最后总结(The End)
1.同义词 2.Flashback 技术 3.连接字符串的写法 4.转义字符 & 特殊运算符 5.文件类型 6.查看参数 & 修改参数 7.AWR 工具 8.学习方法 & 学习 ...