目录
在进行String源码分析之前,我们先来介绍一下char数据类型。
char类型
char类型用于表示单个字符。通常用来表示字符常量。是一个无符号十六进制的值,从u\0000到\uffff。
char数据类型是一个采用UTF-16编码表示Unicode代码点的代码单元。,关于UTF-16编码具体可参考 字符编码笔记:ASCII,Unicode , UTF-8,UTF-16和ISO8859-1(Latin-1)。
下面有两个个概念。
代码点:代码点(code point)是指与一个编码表中的某个字符对应的代码值。在Unicode标准中,代码点采用十六进制书写,并加上前缀U+,例如U+0041就是字母A的代码点。
Unicode的代码点可以分成17个代码级别(code plane)。第一个代码级别称为基本的多语言级别(简称BMP),代码点从U+0000到U+FFFF,其中包括了经典的Unicode代码;其余的16个附加级别,代码点从U+10000到U+FFFFF,其中包括了一些辅助字符。
代码单元:在BMP中,每个字符用16位表示,称为代码单元(code unit)。辅助字符采用一对连续的代码单元进行编码。
因为一个char类型字符代码的是一个代码单元,而UTF-16编码辅助平面字符需要用两个代码单元来表示一个代码点。这可能会带来一些误解,因此,尽量避免用char类型。
一、定义
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence
从该类的声明中我们可以看出String是final类型的,表示该类不能被继承,同时该类实现了三个接口:java.io.Serializable、 Comparable<String>、 CharSequence
二、属性
@Stable
private final byte[] value;
private final byte coder;
private int hash; // Default to 0
private static final long serialVersionUID = -6849794470754667710L;
static final boolean COMPACT_STRINGS;
static {
COMPACT_STRINGS = true;
}
@Native static final byte LATIN1 = 0;
@Native static final byte UTF16 = 1;
-
value表示用来存储字符串对象的值,这里用byte[],@Stable表示该数组不会为null,final表示字符串一旦被初始化后是不会被改变的。
-
coder表示编码方式,Latin1(1个字节)或者UTF16(2个字节或4个字节)。
-
COMPACT_STRINGS 默认将 COMPACT_STRINGS 设置为 true。而如果要取消紧凑的布局可以通过配置 VM 参数-XX:-CompactStrings实现。
-
hash:hash值,默认为0。
String类型的性能优化
从jdk9之后,value的类型由char[]数组变成了byte[]数组。那么为什么要做这样的优化呢?为了节省空间,提高String的性能。
char占用两个字节(16bit),比如字符A,则为0x00 0x41,前面8个bit就是浪费的。也就是说刚好ISO-8859-1(0~255)编码范围的字符都会浪费8个bit,之外的字符则不会浪费。
jdk9之后,用byte[]数组存储字符串,一个byte占一个字节,即8bit。
在不指定字符编码的情况下,会有两种编码方式,Latin1(ISO-8859-1)和UTF-16,当字符都在Latin1范围内的时候就采用Latin1编码方式(紧凑布局),否则使用UTF-16。使用Latin1编码方式的时候,用了byte[]数组之后相对于使用char[]数组,空间节省了一半。
因为改变了String的实现,使用了Latin1和UTF16编码方式,需要增加一个属性coder来表明使用的是哪种编码方式。LATIN1=0;UTF16=1。
字符串对象是 Java 中大量使用的对象,而且我们会轻易大量使用它而从不考虑它的代价,所以对其的空间优化是有必要的,Java9 开始对String类进行优化, 这能帮助我们减少字符串在堆中占用的空间,而且还能减轻GC压力。同时也能看到该空间优化对中文来说意义不大。
三、构造方法
String有很多构造方法,这里介绍几个常见的构造方法。
无参数的构造函数
public String() {
this.value = "".value;
this.coder = "".coder;
}
传入String的构造函数
@HotSpotIntrinsicCandidate
public String(String original) {
this.value = original.value;
this.coder = original.coder;
this.hash = original.hash;
}
传入char[]数组的构造方法
public String(char value[]) {
this(value, 0, value.length, null);
}
String(char[] value, int off, int len, Void sig) {
if (len == 0) {
this.value = "".value;
this.coder = "".coder;
return;
}
if (