[Java] java 的字符集和编码方案

5 篇文章 0 订阅
 Java使用内在的Unicode 表示字符。Unicode 试图用两个字节来表示世界上的所有字符。 这一点可以从java.nio.charset.CharsetEncoder 类中得到证明,他的encode 方法只接受CharBuffer 类型的参数。在java 中一个Char 等于两个字节。

Unicode 的固有支持大大的简化了字符数据处理,但决不是自动的处理字符。您仍需要理解字符映射的工作原理以及如何处理多个字符集。

 

下面是4 个基本概念:
1  Character set(字符集) 字符的集合,也就是,带有特殊语义的符号。字母“A”是一个字符。“%”也是一个字符。没有内在数字价值,与ASCII,Unicode没关系,甚至和电脑也没有任何的直接联系。在电脑产生前,符号就已经存在了。(这里指的就是语言文字,如汉字"我",可以理解为中文的一个字符)

2  Coded character set(被编码的字符集合) 为每个字符集中的字符都指定一个数值(如字符A,可能用数值‘32’来表示)。可以对同一个字符集指定多个被编码的字符集。实际上“被编码的字符集” 也可以被称为字符集映射(Character set mapping),因为它把字符集和数值映射起来了。一般字符集映射由标准的组织定义的,如USASCII, ISO 8859-1, Unicode (ISO 10646-1), and JIS X0201 都是被编码的字符集合。

3  Character-encoding scheme (字符编码方案)是一个一个映射,把被编码的字符集合中的数字(这个数字表示一个字符)映射到八位字节(8 bit字节)的数组中。编码方案定义了如何把字符编码的序列表达为字节序列。字符编码的数值不需要与编码字节相同,也不需要是一对一或一对多个的关系。原则上,把字符集编码和解码近似视为对象的序列化和反序列化。

4  什么是 Charset: Charset 是一个专有名词,他包括 1 被编码的字符集 和 2编码方案。在java 中,用 java.nio.charset 包中的 Charset 类来表示。

可以这样理解: 字符集天然存在,如我们的汉语中的字。但是计算机只能处理0和1,所以必须对字符集编码,变成数字,计算机就能存储和识别了,这样计算机就知道是那个字了。但是为什么要存在字符编码方案呢?
 原因有两点:
  1  虽然我们对字符编码了,但是当需要存储或在网络上传输字符的时候,以这种编码来做合适吗?不一定合适吧。
  2  目前的操作系统都是面向字节的,所以在字符集编码和字节序列之间需要一中转换。

下面来看看例子:

package aaa;

import java.nio.ByteBuffer;
import java.nio.charset.Charset;

public class CharsetTest {
	/**
	 * @param args
	 */
	public static void main(String[] args) {
//		String input = "\u00bfMa\u00f1ana?";
		String input = "我我a";
		String[] charsetNames = { "US-ASCII", "ISO-8859-1", "UTF-8",
				"UTF-16BE", "UTF-16LE", "UTF-16" // , "X-ROT13"
		};
		for (int i = 0; i < charsetNames.length; i++) {
			doEncode(Charset.forName(charsetNames[i]), input);
		}
	}

	private static void doEncode(Charset cs, String input) {
		cs.newEncoder();
		ByteBuffer bb = cs.encode(input);
		System.out.println("Charset: " + cs.name());
		System.out.println("  Input: " + input);
		System.out.println("Encoded: ");
		for (int i = 0; bb.hasRemaining(); i++) {
			int b = bb.get( );
			int ival = ((int) b) & 0xff;
			char c = (char) ival;

			// Keep tabular alignment pretty
			if (i < 10)
				System.out.print(" ");
			// Print index number
			System.out.print(" " + i + ": ");
			// Better formatted output is coming someday...
			if (ival < 16)
				System.out.print("0");
			// Print the hex value of the byte
			System.out.print(Integer.toHexString(ival));
			// If the byte seems to be the value of a
			// printable character, print it. No guarantee
			// it will be.
			if (Character.isWhitespace(c) || Character.isISOControl(c)) {
				System.out.println("");
			} else {
				System.out.println(" (" + c + ")");
			}
		}
		System.out.println ("");
	}
}


运行代码,可以在控制台上看到如下结果:

Charset: US-ASCII
  Input: 我我a
Encoded:
  0: 3f (?)
  1: 3f (?)
  2: 61 (a)

// 分析: 因为ASCII 只识别char 中的最后7位,所以三个字符产生了三个字节。a 是ASCII 的字符,所以可以识别,正确编码。

Charset: ISO-8859-1
  Input: 我我a
Encoded:
  0: 3f (?)
  1: 3f (?)
  2: 61 (a)

Charset: UTF-8
  Input: 我我a
Encoded:
  0: e6 (æ)
  1: 88
  2: 91
  3: e6 (æ)
  4: 88
  5: 91
  6: 61 (a)

// 分析: UTF-8 是不定长的编码,他把下于0x80 的字符(这里指java 的字符,占两个字节)编码成一个字节,而大于0x80 的字符编码成2到6个字节。本例中,把“我”编码成3个字节,"a" 编码成1个字节。

Charset: UTF-16BE
  Input: 我我a
Encoded:
  0: 62 (b)
  1: 11
  2: 62 (b)
  3: 11
  4: 00
  5: 61 (a)

// 分析: UTF-16 系列,把字符编码为2个字节。 所以共6个字节。

Charset: UTF-16LE
  Input: 我我a
Encoded:
  0: 11
  1: 62 (b)
  2: 11
  3: 62 (b)
  4: 61 (a)
  5: 00

Charset: UTF-16
  Input: 我我a
Encoded:
  0: fe (þ)
  1: ff (ÿ)
  2: 62 (b)
  3: 11
  4: 62 (b)
  5: 11
  6: 00
  7: 61 (a)

// 分析: 由于使用UTF-16,没有指定编码后两个字节的顺序,所以多了两个字节,表示采用字节顺序。fe ff 指定了顺序。

 

我的对java 的编码过程也不是很理解,欢迎大家讨论!

参考: <<Java NIO >> 一书

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值