String 被声明为 final,是不可变的,它也不可被继承。
Java 9对String的行为进行了2个主要更改,以降低内存使用量并提高性能。
在 JDK 8 中,String 是使用 char[] 数组实现的,构造函数用char[] 数组来实例化的时候,只是做一下copy。
public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
/** Cache the hash code for the string */
private int hash; // Default to 0
public String(char value[]) {
this.value = Arrays.copyOf(value, value.length);
}
}
到了 JDK 9 ,String 类的实现改用 byte[] 数组实现,同时使用 coder 来标识使用了哪种编码,使用LATIN1还是UTF-16,这个是在String生成的时候自动的,如果字符串中都是能用LATIN1就能表示的就是0,否则就是UTF-16.
java中char是16位UTF16编码的,那么byte[] 数组是如何存下char[] 数组的?
具体实现如下:
这里是通过StringUTF16.compress(value, off, len);
来判断,如果char[] 数组存在 value > 0xFF 的值时,就返回null,见下图:
如果char[] 数组所有的字符都是小于0xFF,那么正好让一个byte对应一个char,String构造到此结束。
只要存在一个char > 0xFF,那么将会把byte数组的长度改为两倍char数组的长度,用两个字节存放一个char ,见下图:
由于实现机制的变动,所有的String方法都重新实现了一遍,但对外的接口还是保持一致的。重构带来的最大好处就是在字符串中所有的字符都小于0xFF的情况下,会节省一半的内存。
使用byte数组可以减少一半的内存,byte使用一个字节来存储一个char字符,char使用两个字节来存储一个char字符。只有当一个char字符大小超过0xFF时,才会将byte数组变为原来的两倍,用两个字节存储一个char字符。
0xFF
以0x
开始的数据表示16进制,0xFF
换成十进制为255。
<<
是左移运算
1 << 28 就是左移28位;根据计算机中左移1位相当于乘以2,那么1左移28位就等于 2的28次方。
计算规则:n << m
相当于 n*2m
3<<2
相当于 3*22 值为 12