Java开发者必须牢记:在Java中字符仅以一种形式存在,那就是Unicode(不选择任何特定的编码,直接使用他们在字符集中的编号,这是统一的唯一方法)。由于java采用unicode编码,char 在java中占2个字节。2个字节(16位)来表示一个字符。

这里的Java中是指在JVM中、在内存中、在代码里声明的每一个char、String类型的变量中。

例如:

 
1
2
3
4
5
6
7
System.out.println(System.getProperty("file.encoding"));
char han = '永';
System.out.format("%x", (short)han);//对第二个参数(短整型)格式化为十六进制输出,0x开头
//输出6c38
char han1 = 0x6c38;
System.out.println(han1);
//输出永

也就是说,只要我们正确地读入了汉字“永”字,那么它在内存中的表示形式一定是0x6c38,没有其他任何值能替代这个字。

JVM的折中约定使得一个字符分为两部分:JVM内部和OS的文件系统。在JVM内部,统一使用Unicode表示,当这个字符被从JVM内部移到外部(即保存为文件系统中的一个文件的内容时),就进行了编码转换,使用了具体的编码方案。因此可以说所有的编码转换只发生在边界的地方,JVM和OS的交界处,也就是各种输入/输出流(或者Reader,Writer类)起作用的地方。

所有的I/O基本上可以分为两大阵营:面向字符的输入/输出流;面向字节的输入/输出流。这个“面向”是指这些类在处理输入/输出的时候,在哪个意义上保持一致。

如果面向字节,那么这类工作要保证系统中的文件二进制内容和读入JVM内部的二进制内容一致,不能变换任何0和1的顺序。这种输入/输出方式很适合诸如视频文件或者音频文件,因为不需要变换任何文件内容。

而面向字符的I/O是指希望系统中的文件的字符和读入内存的“字符”要一致。例如:我们的中文版XP系统上有一个GBK的文本文件,其中有一个“永”字,我们不关心这个字的GBK编码是什么,只希望在使用面向字符的I/O把它读入内存并保存在一个char型变量中时,I/O系统不要直接把“永”字的GBK编码放到这个字符(char)型变量中,我们不关心这个char型变量具体的二进制内容到底是多少,只希望这个字符读进来之后仍然是“永”字。

从这个意义上可以看出,面向字符的I/O类,也就是Reader和Writer类,实际上隐式做了编码转换,在输出时,将内存中的Unicode字符使用系统默认编码方式进行了编码,而在输入时,将文件系统中已经编码过的字符使用默认编码方案进行了还原。这里要注意,Reader和Writer只会使用这个默认的编码来做转换,而不能为一个Reader和Writer指定转换时使用的编码。这也意味着,如果使用中文版WindowsXP系统,其中存放了一个UTF8编码的文件,当采用Reader类来读入的时候,它还会用GBK来转换,转换后的内容当然不对。这其实是一种傻瓜式的功能提供方式,对大多数初级用户(以及不需要跨平台的高级用户,windows一般采用GBK,linux一般采用UTF8)来说反而是一件好事。

如果用到GBK编码以外的文件,就必须采用编码转换:一个字符与字节之间的转换。因此,Java的I/O系统中能够指定转换编码的地方,也就是在字符与字节转换的地方,那就是InputStremReader与OutputStreamWriter。这两个类是字节流和字符流的适配器类,它们承担编码转换的任务。

既然java是用unicode来编码字符,”我”这个中文字符的unicode就是2个字节。String.getBytes(encoding)方法是获取指定编码的byte数组表示,通常gbk/gb2312是2个字节,utf-8是3个字节。如果不指定encoding则取系统默认的encoding。

例如

 
1
2
3
4
5
6
7
8
9
10
11
//UTF8汉字占三个字节
b = str.getBytes("UTF-8");
System.out.println("UTF8编码格式下,一个汉字占" + b.length + "字节");
 
//混乱,很诡异,不理解!!!!!!
b = str.getBytes("UTF-16");
System.out.println("UTF16编码格式下,一个汉字占" + b.length + "字节");
 
//ANSI码小于128的字符占一个字节,其余占俩字节
b = str.getBytes();
System.out.println("默认编码" + System.getProperty("file.encoding") + "编码格式下,一个汉字占" + b.length + "字节");

由于JDK是国际版的,在编译的时候,如果我们没有用-encoding参数指定我们的JAVA源程序的编码格式,则javac.exe首先获得我们操作系统默认采用的编码格式,也即在编译java程序时,若我们不指定源程序文件的编码格式,JDK首先获得操作系统的file.encoding参数(它保存的就是操作系统默认的编码格式,如WIN2k,它的值为GBK),然后JDK就把我们的java源程序从file.encoding编码格式转化为JAVA内部默认的UNICODE格式放入内存中。然后,javac把转换后的unicode格式的文件进行编译成.class类文件,此时.class文件是UNICODE编码的,它暂放在内存中,紧接着,JDK将此以UNICODE编码的编译后的class文件保存到我们的操作系统中形成我们见到的.class文件。对我们来说,我们最终获得的.class文件是内容以UNICODE编码格式保存的类文件,它内部包含我们源程序中的中文字符串,只不过此时它己经由file.encoding格式转化为UNICODE格式了。

Java与编码问题串讲之二–如何理解java采用Unicode编码的更多相关文章

  1. 如何理解java采用Unicode编码

    http://blog.csdn.net/gjb724332682/article/details/43229563 Java中字符仅以一种形式存在,那就是Unicode.由于java采用unicod ...

  2. java提高篇(二)-----理解java的三大特性之继承

    在<Think in java>中有这样一句话:复用代码是Java众多引人注目的功能之一.但要想成为极具革命性的语言,仅仅能够复制代码并对加以改变是不够的,它还必须能够做更多的事情.在这句 ...

  3. 从 CPU 讲起,深入理解 Java 内存模型!

    Java 内存模型,许多人会错误地理解成 JVM 的内存模型.但实际上,这两者是完全不同的东西.Java 内存模型定义了 Java 语言如何与内存进行交互,具体地说是 Java 语言运行时的变量,如何 ...

  4. app开发历程————服务器端生成JSON格式数据,采用Unicode编码,隐藏中文

    今天,问以前的同事,他们写接口按什么编码,怎么看到有\u的一些看不懂的内容,一问,原来是信息隐藏,防止信息泄漏. 然后在网上查了Java如何把中文转换成unicode编码,转自:http://blog ...

  5. Java集合详解(一):全面理解Java集合

    概述 Java所有集合类都在java.util包下,支持并发的集合在java.util.concurrent(juc)包下. 集合与数组区别: 数组大小是固定的,集合大小可以根据使用情况进行动态扩容. ...

  6. Java虚拟机运行时栈帧结构--《深入理解Java虚拟机》学习笔记及个人理解(二)

    Java虚拟机运行时栈帧结构(周志明书上P237页) 栈帧是什么? 栈帧是一种数据结构,用于虚拟机进行方法的调用和执行. 栈帧是虚拟机栈的栈元素,也就是入栈和出栈的一个单元. 2018.1.2更新(在 ...

  7. VS2010与VS2013中的多字节编码与Unicode编码问题

    1. 多字节字符与单字节字符 char与wchar_t 我们知道C++基本数据类型中表示字符的有两种:char.wchar_t.  char叫多字节字符,一个char占一个字节,之所以叫多字节字符是因 ...

  8. 【由浅入深理解java集合】(二)——集合 Set

    上一篇文章介绍了Set集合的通用知识.Set集合中包含了三个比较重要的实现类:HashSet.TreeSet和EnumSet.本篇文章将重点介绍这三个类. 一.HashSet类 HashSet简介 H ...

  9. 别翻了,这篇文章绝对让你深刻理解java类的加载以及ClassLoader源码分析【JVM篇二】

    目录 1.什么是类的加载(类初始化) 2.类的生命周期 3.接口的加载过程 4.解开开篇的面试题 5.理解首次主动使用 6.类加载器 7.关于命名空间 8.JVM类加载机制 9.双亲委派模型 10.C ...

随机推荐

  1. [转] lua 获取本地当月天数

    亲测,无误. 原文传送门:lua 获取本地当月天数 开发中有用到,记录一下. local year,month = os.date("%Y", os.time()), os.dat ...

  2. linux管道命令学习(一)

    继续看鸟哥私房菜,看一直很想弄懂的管道命令(pipe).第一次知道管道这个词还是在学django的时候,模板里的过滤器很像这里的管道.管道就是将输出在标准输出中的信息一次次处理最终打印在标准输出中,所 ...

  3. 使用 Jackson 树模型(tree model) API 处理 JSON

    http://blog.csdn.net/gao1440156051/article/details/54091702 http://blog.csdn.net/u010003835/article/ ...

  4. docker之创建MariaDB镜像的方法

    一.基于commit命令方式创建 docker的安装 ? 1 2 3 [root@test01 ~]# yum install docker [root@test01 ~]# systemctl en ...

  5. Linux各个文件夹的作用~~~非常实用!!

    linux下的文件结构,看看每个文件夹都是干吗用的/bin   二进制可执行命令 /dev 设备特殊文件 /etc 系统管理和配置文件 /etc/rc.d 启动的配置文件和脚本 /home 用户主目录 ...

  6. 消息队列RabbitMQ基础知识详解

    一: 什么是MQ? MQ全称为Message Queue, 消息队列(MQ)是一种应用程序对应用程序或者模块对模块的通信方法.MQ是消费-生产者模型的一个典型的代表,一端往消息队列中不断写入消息,而另 ...

  7. C#学习笔记(24)——C#将PPT批量转为JPG(最简单的方法)

    说明(2017-8-1 11:15:46): 1. 哈哈,我就说微软肯定有自己的办法,把PPT转成图片. 2. 主要是要引入两个微软自己的程序集,vs里自带直接添加引用,注意一下版本,12.0是off ...

  8. iOS隐藏状态栏

    1.整个项目隐藏状态栏 在Targets->General->勾选中Hide status bar . 整个项目隐藏状态栏 2.单个界面隐藏状态栏,例如登录注册页面 1.首先在info.p ...

  9. Oracle 安装报错 [INS-06101] IP address of localhost could not be determined 解决方法

    安装Oracle 11gR2,报错:[INS-06101] IP address of localhost could not be determined 出现这种错误是因为主机名和/etc/host ...

  10. 基于HTML5功能强大的滑块幻灯片

    分享一款功能强大的HTML5滑块幻灯片.这是一款基于jQuery+HTML5实现的图片切换幻灯片代码.效果图如下: 在线预览   源码下载 实现的代码. html代码: <section cla ...