面试题:一个汉字占多大空间。
事实上这个问题我了解不深的,知道结论不知道为什么。借此梳理下认识。

先回想下java基本类型
一基本类型 :
简称四类八种,声明变量的同一时候分配了空间。举比例如以下:
  Int a =1;
一、4种整型 
    byte      1字节           -128——127 
    short     2 字节         -32,768 —— 32,767 
    int       4 字节          -2,147,483,648 ——2,147,483,647(超过20亿) 
    long      8 字节   -9,223,372,036,854,775,808——9,223,372,036854,775,807 
    凝视:java中全部的数据类所占领的字节数量与平台无关,java也没有任何无符号类型 
二、 2种浮点类型 
    float    4 字节         32位IEEE 754单精度(有效位数 6 – 7位) 
    double   8 字节         64位IEEE 754双精度(有效位数15位) 
三、1种Unicode编码的字符单元 
    char    2 字节          整个Unicode字符集 
四、1种真值类型 
boolean    1 位             True或者false 
 二 引用类型:
除了四类八种基本类型外,全部的类型都称为引用类型:类class 、接口interface 、数组array 
基本类型是值传递。引用类型是引用传递。

MyDate a,b。                       //在内存开辟两个引用空间

a  =  new MyDate();    //开辟MyDate对象的数据空间,并把该空间的首地址赋给a

b  =  a。                      //将a存储空间中的地址写到b的存储空间中

一个具有值类型(value type)的数据存放在栈内的一个变量中。即是在栈中分配内存空间。直接存储所包括的值,其值就代表数据本身。值类型的数据具有较快的存取速度。

一个具有引用类型(reference type)的数据并不驻留在栈中,而是存储于堆中。即是在堆中分配内存空间,不直接存储所包括的值,而是指向所要存储的值,其值代表的是所指向的地址。当訪问一个具有引用类型的数据时。须要到栈中检查变量的内容,该变量引用堆中的一个实际数据。引用类型的数据比值类型的数据具有更大的存储规模和较低的訪问速度。

************************背景结束。正文開始************************

事实上关于上面引用类型如:String,还有常见集合有非常多细化知识点,本篇写不完。

看下问题的简单回答:

简单汉字:utf-8 的汉字占3个字节  gbk 是两个字节。 
  先了解下主要的单位:
1、比特(bit)即一个二进制位。比如100011就是6比特。
2、字节(byte)。这是计算机中数据类型最主要的单位了,8bit组成1byte。 
为什么要编码?原因就是:
1)一个字节一共能够用来表示256种不同的状态,每个状态相应一个符号,就是256个符号,从0000000到11111111。
 2)表示的符号太多,无法用一个字节来全然表示。要解决这个矛盾必须须要一个新的数据结构 char,从 char 到 byte 必须编码。
以下介绍下常见的编码规则,所谓的规则就是为转换成计算机所能理解的语言。
  • ASCII 码
学过计算机的人都知道 ASCII 码。总共同拥有 128 个,用一个字节的低 7 位表示,0~31 是控制字符如换行回车删除等。32~126 是打印字符。能够通过键盘输入并且能够显示出来。这128个符号(包括32个不能打印出来的控制符号),仅仅占用了一个字节的后面7位,最前面的1位统一规定为0。
  • ISO-8859-1
128 个字符显然是不够用的,于是 ISO 组织在 ASCII 码基础上又制定了一些列标准用来扩展 ASCII 编码,它们是 ISO-8859-1~ISO-8859-15。当中 ISO-8859-1 涵盖了大多数西欧语言字符,全部应用的最广泛。ISO-8859-1 仍然是单字节编码,它总共能表示 256 个字符。
  • GB2312
它的全称是《信息交换用汉字编码字符集 基本集》。它是双字节编码,总的编码范围是 A1-F7,当中从 A1-A9 是符号区,总共包括 682 个符号,从 B0-F7 是汉字区,包括 6763 个汉字。
  • GBK
全称叫《汉字内码扩展规范》。是国家技术监督局为 windows95 所制定的新的汉字内码规范,它的出现是为了扩展 GB2312,增加很多其它的汉字,它的编码范围是 8140~FEFE(去掉 XX7F)总共同拥有 23940 个码位,它能表示 21003 个汉字,它的编码是和 GB2312 兼容的,也就是说用 GB2312 编码的汉字能够用 GBK 来解码,并且不会有乱码。
  • UTF-16
说到 UTF 必须要提到 Unicode(Universal Code 统一码),ISO 试图想创建一个全新的超语言字典。世界上全部的语言都能够通过这本字典来相互翻译。 可想而知这个字典是多么的复杂,关于 Unicode 的具体规范能够參考相应文档。 Unicode 是 Java 和 XML 的基础,以下具体介绍 Unicode 在计算机中的存储形式。须要注意的是,Unicode仅仅是一个符号集,它仅仅规定了符号的二进制代码,却没有规定这个二进制代码应该怎样存储。 比方,汉字"严"的unicode是十六进制数4E25,转换成二进制数足足有15位(100111000100101)。也就是说这个符号的表示至少须要2个字节。表示其它更大的符号,可能须要3个字节或者4个字节。甚至很多其它。 UTF-16 具体定义了 Unicode 字符在计算机中存取方法。UTF-16 用两个字节来表示 Unicode 转化格式。这个是定长的表示方法,任何字符都能够用两个字节表示,两个字节是 16 个 bit,所以叫 UTF-16。UTF-16 表示字符非常方便。每两个字节表示一个字符,这个在字符串操作时就大大简化了操作。这也是 Java 以 UTF-16 作为内存的字符存储格式的一个非常重要的原因。
  • UTF-8
UTF-16 统一採用两个字节表示一个字符,尽管在表示上非常easy方便,可是也有其缺点,有非常大一部分字符用一个字节就能够表示的如今要两个字节表示,存储空间放大了一倍,在如今的网络带宽还非常有限的今天。这样会增大网络传输的流量,并且也不是必需。而 UTF-8 採用了一种变长技术,每个编码区域有不同的字码长度。 不同类型的字符能够是由 1~6 个字节组成。 UTF-8 有以下编码规则: 假设一个字节,最高位(第 8 位)为 0,表示这是一个 ASCII 字符(00 - 7F)。 可见。全部 ASCII 编码已经是 UTF-8 了。 假设一个字节。以 11 开头,连续的 1 的个数暗示这个字符的字节数,比如:110xxxxx 代表它是双字节 UTF-8 字符的首字节。
反复一遍,这里的关系是,UTF-8是Unicode的实现方式之中的一个。
下表总结了编码规则,字母x表示可用编码的位。 Unicode符号范围 | UTF-8编码方式
(十六进制) | (二进制)
--------------------+---------------------------------------------
0000 0000-0000 007F | 0xxxxxxx
0000 0080-0000 07FF | 110xxxxx 10xxxxxx
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
在 Java 开发中除了 I/O 涉及到编码外。最经常使用的应该就是在内存中进行字符到字节的数据类型的转换。 上面介绍了常见的编码格式,以下结合样例看看java中编解码方式: 我们一汉字“严”为例进行測试。

public class LengthTest {

public static void main(String[] args) throws Exception{
String name = "严";
byte[] utf8 = name.getBytes("UTF-8");
System.out.println(utf8.length);
System.out.print("UTF8:");toHex(utf8);
byte[] gbk = name.getBytes("GBK");
System.out.print("GBK:");toHex(gbk);
String unicodeStr =Integer.toHexString("严".charAt(0) );
System.out.println("unicode:"+unicodeStr); //
//unicode转汉字
StringBuffer sb = new StringBuffer();
String str[] = unicodeStr.toUpperCase().split("U");
for(int i=0;i<str.length;i++){
if(str[i].equals("")) continue;
char c = (char)Integer.parseInt(str[i].trim(),16);
sb.append(c);
}
System.out.println(sb.toString());
}
public static void toHex(byte[] b) {
for (int i = 0; i < b.length; i++) {
System.out.printf("%x " , b[i]);
}
System.out.println();
}
}

我们把 name 字符串依照前面说的几种编码格式进行编码转化成 byte 数组,然后以 16 进制输出,我们先看一下 Java 是怎样进行编码的。

首先依据指定的 charsetName 通过 Charset.forName(charsetName) 设置 Charset 类,然后依据 Charset 创建 CharsetEncoder 对象。再调用 CharsetEncoder.encode 对字符串进行编码,不同的编码类型都会相应到一个类中,实际的编码过程是在这些类中完毕的。以下是 String. getBytes(charsetName) 编码过程的时序图
以下是相应的StringCoding的代码:

static byte[] encode(String charsetName, char[] ca, int off, int len)
throws UnsupportedEncodingException
{
StringEncoder se = deref(encoder);
String csn = (charsetName == null) ? "ISO-8859-1" : charsetName;
if ((se == null) || !(csn.equals(se.requestedCharsetName())
|| csn.equals(se.charsetName()))) {
se = null;
try {
Charset cs = lookupCharset(csn);
if (cs != null)
se = new StringEncoder(cs, csn);
} catch (IllegalCharsetNameException x) {}
if (se == null)
throw new UnsupportedEncodingException (csn);
set(encoder, se);
}
return se.encode(ca, off, len);
}

从上图能够看出依据 charsetName 找到 Charset 类,然后依据这个字符集编码生成 CharsetEncoder。这个类是全部字符编码的父类。针对不同的字符编码集在其子类中定义了怎样实现编码,有了 CharsetEncoder 对象后就能够调用 encode 方法去实现编码了。这个是 String.getBytes 编码方法。其它的如 StreamEncoder 中也是相似的方式。以下看看不同的字符集是怎样将前面的字符串编码成 byte 数组的?

依照GBK方式:

以下是大神 君山写的,我在jdk源代码找不到相应查表规则,仅仅有c2b接口。

GB2312 相应的 Charset 是 sun.nio.cs.ext. EUC_CN 而相应的 CharsetDecoder 编码类是 sun.nio.cs.ext. DoubleByte,GB2312 字符集有一个 char 到 byte 的码表,不同的字符编码就是查这个码表找到与每个字符的相应的字节,然后拼装成 byte 数组。查表的规则例如以下:

 c2b[c2bIndex[char >> 8] + (char & 0xff)]
GBK 编码是兼容 GB2312 编码的。它们的编码算法也是一样的。

不同的是它们的码表长度不一样。GBK 包括的汉字字符很多其它。

所以仅仅要是经过 GB2312 编码的汉字都能够用 GBK 进行解码,反过来则不然。

依照utf-8格式编码:

为加深理解:对照上面utf-8编码表。已知"严"的unicode是4E25,相应二进制(100111000100101),依据上表,能够发现4E25处在第三行的范围内(0000 0800-0000 FFFF),因此"严"的UTF-8编码须要三个字节,即格式是"1110xxxx 10xxxxxx 10xxxxxx"。

然后。从"严"的最后一个二进制位開始。依次从后向前填入格式中的x。多出的位补0。这样就得到了。"严"的UTF-8编码是"11100100 10111000 10100101",转换成十六进制就是E4B8A5。

以下结合代码执行结果,能够更好的理解

至此。能够理解题目的答案了。

事实上Windows平台还有一个简单的办法,就是记事本能够辅助实现不同编码转换。

打开文件后。点击"文件"菜单中的"另存为"命令,会跳出一个对话框。在最底部有一个"编码"的下拉条。



里面有四个选项:ANSI。Unicode,Unicode big endian 和 UTF-8。

1)ANSI是默认的编码方式。对于英文文件是ASCII编码。对于中文简体文件是GB2312编码(仅仅针对Windows中文简体版,假设是繁体中文版会採用Big5码)。

2)Unicode编码指的是UCS-2编码方式,即直接用两个字节存入字符的Unicode码。

这个选项用的little endian格式。

3)Unicode big endian编码与上一个选项相相应。我在下一节会解释little endian和big endian的涵义。

4)UTF-8编码,也就是上一节谈到的编码方法。

选择完"编码方式"后,点击"保存"button,文件的编码方式就立马转换好了。

7. Little endian和Big endian

上一节已经提到,Unicode码能够採用UCS-2格式直接存储。

以汉字"严"为例,Unicode码是4E25。须要用两个字节存储,一个字节是4E。还有一个字节是25。

存储的时候。4E在前,25在后,就是Big endian方式;25在前,4E在后,就是Little endian方式。

这两个古怪的名称来自英国作家斯威夫特的《格列佛游记》。在该书中,小人国里爆发了内战。战争起因是人们争论。吃鸡蛋时究竟是从大头(Big-Endian)敲开还是从小头(Little-Endian)敲开。为了这件事情。前后爆发了六次战争,一个皇帝送了命。还有一个皇帝丢了王位。

因此,第一个字节在前,就是"大头方式"(Big endian)。第二个字节在前就是"小头方式"(Little endian)。

那么非常自然的,就会出现一个问题:计算机怎么知道某一个文件究竟採用哪一种方式编码?

Unicode规范中定义,每个文件的最前面分别增加一个表示编码顺序的字符,这个字符的名字叫做"零宽度非换行空格"(ZERO WIDTH NO-BREAK SPACE)。用FEFF表示。这正好是两个字节。并且FF比FE大1。

假设一个文本文件的头两个字节是FE FF,就表示该文件採用大头方式;假设头两个字节是FF FE,就表示该文件採用小头方式。
*****************************

几种编码格式的比較

对中文字符后面四种编码格式都能处理,GB2312 与 GBK 编码规则相似,可是 GBK 范围更大,它能处理全部汉字字符。所以 GB2312 与 GBK 比較应该选择 GBK。UTF-16 与 UTF-8 都是处理 Unicode 编码。它们的编码规则不太同样,相对来说 UTF-16 编码效率最高,字符到字节相互转换更简单,进行字符串操作也更好。它适合在本地磁盘和内存之间使用,能够进行字符和字节之间高速切换,如 Java 的内存编码就是採用 UTF-16 编码。可是它不适合在网络之间传输,由于网络传输easy损坏字节流,一旦字节流损坏将非常难恢复,想比較而言 UTF-8 更适合网络传输,对 ASCII 字符採用单字节存储,另外单个字符损坏也不会影响后面其它字符,在编码效率上介于 GBK 和 UTF-16 之间,所以 UTF-8 在编码效率上和编码安全性上做了平衡,是理想的中文编码方式。 有些扯远了。理解了这些,也就不easy出现乱码问题。 另外知乎上大神给出了“内码”“外码”的概念,更加easy理解. https://www.zhihu.com/question/27562173/answer/37188642
參考:
http://www.cnblogs.com/bluestorm/archive/2012/07/30/2615034.html
http://www.ibm.com/developerworks/cn/java/j-lo-chinesecoding/
http://blog.csdn.net/fancylovejava/article/details/10142391

java梳理-一个汉字占多大空间的更多相关文章

  1. JAVA中一个汉字占多少个字符(转载)

    1.先说重点: 不同的编码格式占字节数是不同的,UTF-8编码下一个中文所占字节也是不确定的,可能是2个.3个.4个字节: 2.以下是源码: 1 @Test 2 public void test1() ...

  2. mysql和oracle的一个汉字占几个字符

    以前一直使用oracle11g,一个汉字占3个字节,所以在操作mysql时也一直这样分配长度. 今天测试了下发现不对了 可以看到第一个的长度确实是15,但是第二个为什么是5? 在网上找到资料:char ...

  3. Java一个汉字占几个字节(详解与原理)

    1.先说重点: 不同的编码格式占字节数是不同的,UTF-8编码下一个中文所占字节也是不确定的,可能是2个.3个.4个字节: 2.以下是源码: @Test public void test1() thr ...

  4. Java一个汉字占几个字节(详解与原理)(转载)

    1.先说重点: 不同的编码格式占字节数是不同的,UTF-8编码下一个中文所占字节也是不确定的,可能是2个.3个.4个字节: 2.以下是源码: 1 @Test 2 public void test1() ...

  5. 请问utf-8的中文是一个汉字占三个字节长度吗?

    这是个好问题,可以当作一个笔试题.先从字符编码讲起. 1.美国人首先对其英文字符进行了编码,也就是最早的ascii码,用一个字节的低7位来表示英文的128个字符,高1位统一为0: 2.后来欧洲人发现尼 ...

  6. 【转】utf-8的中文是一个汉字占三个字节长度

    因为看到百度里面这个人回答比较生动,印象比较深刻,所以转过来做个笔记 原文链接 https://zhidao.baidu.com/question/1047887004693001899.html 知 ...

  7. 为什么Java中一个char能存下一个汉字

    在Java中,char的长度是2字节,即16位,2的16次方是65536. 1.如果采用utf-8编码,一个汉字占3个字节,char为什么还能存下一个汉字呢? 参考:https://developer ...

  8. python中一个汉字点3个字节? utf-8

    今天发现了一个汉字占了3个字节,一开始以为是两个呢,字符串切片时总出现乱码,后来才发现一个中文占3个字节.这才解决了乱码问题 原来  1. utf-8 编码中,一个汉字占三个字节.英文字母是一个占用一 ...

  9. ORACLE中一个字符占多少字节?

    问题描述 或许你会说一个中文字符占2个字节,这是一定的?如何计算一个字符串的字节数? 解决方案 在oracle中一个字符特别是中文占几个字节是不同的. 比如我创立一个表create table tes ...

随机推荐

  1. 【数据结构】Trie树

    数据结构--Trie树 概念 Trie树,又称字典树.前缀树,是一种树形结构,是一种哈希树的变种.典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计 ...

  2. RxSwift 系列(三)

    RxSwift 系列(三) -- Combination Operators 前言 本篇文章将要学习如何将多个Observables组合成一个Observable.Combination Operat ...

  3. codevs 1230【pb_ds】

    题目链接[http://codevs.cn/problem/1230/] 题意:给出n个正整数,然后有m个询问,每个询问一个整数,询问该整数是否在n个正整数中出现过. 题解:很简单的一道题,可以选择用 ...

  4. 2018BNU校赛总决赛

    题解是qls的题解我就懒得写了23333 A塞特斯玛斯塔 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32768K,其他语言65536K 64bit IO Format: %lld ...

  5. 【容斥原理】【推导】【树状数组】Gym - 101485G - Guessing Camels

    题意:给你三个1~n的排列a,b,c,问你在 (i,j)(1<=i<=n,1<=j<=n,i≠j),有多少个有序实数对(i,j)满足在三个排列中,i都在j的前面. 暴力求的话是 ...

  6. win7环境下一次浅谈栈溢出

    在我们的生活中,存在的许许多多的漏洞,下面像大家介绍的就是平时比较常见的栈溢出漏洞的实践过程. 下面,我们用一个非常简单的例子来让大家对栈溢出漏洞有个直观的认识. 这是一个简单的密码验证程序,但因为代 ...

  7. [SimpleOJ238]宝藏探寻

    题目大意: 给你一棵带点权的n个结点的树,有m次询问,每次从树上删掉一条路径(u,v),问删掉每条路径后各个连通块权值和的平方之和. 每次询问是独立的. 思路: 首先对树遍历一遍求出每棵子树的权值和. ...

  8. 洛谷P1462 通往奥格瑞玛的道路

    题目背景 在艾泽拉斯大陆上有一位名叫歪嘴哦的神奇术士,他是部落的中坚力量 有一天他醒来后发现自己居然到了联盟的主城暴风城 在被众多联盟的士兵攻击后,他决定逃回自己的家乡奥格瑞玛 题目描述 在艾泽拉斯, ...

  9. BSGS 模板

    模板如下: 扩展版本: 求解a^k=b %p 求k,最小的k一定小于p,否则会重复,否则无解 *********************** gcd(a,p)=1时 设k=mi+v m=sqrt(p) ...

  10. ReactNative-地图导航-iOS

    需求描述 项目中,要求接入导航功能,包括“百度map.高德map”. 方案分析 原生开发角度分析 从原生开发的角度分析的话,常规的思路可能是 分别取百度.高德官网,下载对应的SDK然后集成到本地: 创 ...