从byte[]和char[]的不同,看字符串的编码问题
一、概述
众所周知:
- byte 是字节数据类型 ,是有符号型的,占1 个字节;大小范围为-128—127 。
- char 是字符数据类型 ,是无符号型的,占2字节(Unicode码 );大小范围 是0—65535 ;
char是一个16位二进制的Unicode字符,JAVA用char来表示一个字符 。
可能看到上面这句话的时候,往往不会在意char是不是Unicode字符,当时它却是我们理清楚编码的关键。
二、编码类型
一说到编码,就会想到GBK和utf8,到底这些编码都是干什么的呢?
- ASCII:严格来说,我们提到编码的时候,没必要说ASCII的,因为它不支持中文,它就不会被我们日常拿来用做字符串的编码。它对应的Charset是US-ASCII
- GBK:国人就定义了一套编码规则,中文两个字节,英文一个字节,注意是字节。它对应的Charset是GBK。
- UTF-8:UTF是 Unicode Translation Format,即把Unicode转做某种格式的意思,针对Unicode的一种可变长度字符编码。它可以用来表示Unicode标准中的任何字符,而且其编码中的第一个字节仍与ASCII相容,中文三个字节,英文一个字节。它对应的Charset是UTF-8。
- Unicode:Unicode只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。UTF-8是Unicode的实现方式之一。如果用
Charset.forName("Unicode")
,结果是UTF_16。
三、byte[]和char[]
byte[]是字节数组,而char[]是字符数组。
- 一个英文,存储在byte[]中,长度是1,存储在char[]也是1。
- 一个中文,存储在byte[]中,utf8长度是3,存储在char[]是1。
3.1 String和StringBuilder看字节数组和字符数组
String的构造方法有根据字符数组和字节数组创建字符对象,StringBuilder中只有添加字符数组的方法。 String:
代码语言:javascript复制public String(char value[]) {
this.value = Arrays.copyOf(value, value.length);
}
public String(byte bytes[]) {
this(bytes, 0, bytes.length);
}
public String(byte bytes[], String charsetName)
throws UnsupportedEncodingException {
this(bytes, 0, bytes.length, charsetName);
}
public String(byte bytes[], Charset charset) {
this(bytes, 0, bytes.length, charset);
}
StringBuilder:
代码语言:javascript复制public StringBuilder append(char[] str) {
super.append(str);
return this;
}
所以,有时候会疑惑,为什么StringBuilder不需要考虑编码的问题,这是因为StringBuilder本身是一个char[] value
.
而String本身也是个char value[]
,但是却将byte[]装成了char[]:
static char[] decode(String charsetName, byte[] ba, int off, int len)
throws UnsupportedEncodingException
{
StringDecoder sd = deref(decoder);
String csn = (charsetName == null) ? "ISO-8859-1" : charsetName;
if ((sd == null) || !(csn.equals(sd.requestedCharsetName())
|| csn.equals(sd.charsetName()))) {
sd = null;
try {
Charset cs = lookupCharset(csn);
if (cs != null)
sd = new StringDecoder(cs, csn);
} catch (IllegalCharsetNameException x) {}
if (sd == null)
throw new UnsupportedEncodingException(csn);
set(decoder, sd);
}
return sd.decode(ba, off, len);
}
所以,字符串就是存储的字符,不叫字节串,字节转字符需要指定编码,字符转字节也需要指定编码。
3.1 InputStream和InputStreamReader看字节数组和字符数组
InputStream无论是网络流还是文件流,都是不需要自定编码,如:
代码语言:javascript复制public FileInputStream(String name) throws FileNotFoundException {
this(name != null ? new File(name) : null);
}
public ByteArrayInputStream(byte buf[]) {
this.buf = buf;
this.pos = 0;
this.count = buf.length;
}
因为它本身就是字节,属于存储属性的字节,已经有编码含义。
InputStreamReader需要指定编码:
代码语言:javascript复制public InputStreamReader(InputStream in, String charsetName)
throws UnsupportedEncodingException
{
super(in);
if (charsetName == null)
throw new NullPointerException("charsetName");
sd = StreamDecoder.forInputStreamReader(in, this, charsetName);
}
类似与String, 它需要将字节转成字符,就需要指定编码。
四、结论
一个字就是一个字符,一个字可以有多个字节。不同的编码下,一个字的字节数不同。