据我所知 Java 开发人员几乎任什么时候候都会想到 String,字符串确实已经成为最经常使用的类了,并且是大量使用。咱们都知道,String 实际上是封装了字符,里面必须由字符或字节数组来存放,从 Java9 开始 Java 语言开发者对 String 作了一些空间的优化。数组
JDK9 以前的库的 String 类的实现使用了 char 数组来存放字符串,char 占用16位,即两字节。bash
private final char value[];
复制代码
这种状况下,若是咱们要存储字符A
,则为0x00
0x41
,此时前面的一个字节空间浪费了。但若是保存中文字符则不存在浪费的状况,也就是说若是保存 ISO-8859-1 编码内的字符则浪费,以外的字符则不会浪费。并发
而 JDK9 后 String 类的实现使用了 byte 数组存放字符串,每一个 byte 占用8位,即1字节。机器学习
private final byte[] value
复制代码
String 支持多种编码,但若是不指定编码的话,它可能使用两种编码,分别为 LATIN1 和 UTF16。LATIN1 可能比较陌生,其实就是 ISO-8859-1 编码,属于单字节编码。而 UTF16 为双字节编码,它使用1个或2个16位长的空间存储。分布式
压缩的字符对象主要是在 ISO-8859-1 编码内的字符,好比英语字母数字还有其余常见符号。为了更好理解咱们看下图,假如咱们有一个“what”字符串,那么若是在 Java9 以前,它的存储是按以下队列排列的,能够看到每一个字符都须要16位来存储,而高字节位都为0,这个其实就是浪费了。布局
而在 Java9 后,它的存储的排列则很紧凑了,以下图,只需四个字节便可。学习
但若是是“哈a”,则布局为下图,因此若是字符串中的字符一旦包含了不在 ISO-8859-1 编码内的字符,则一样仍是统一使用16位长度来保存。优化
Java9 的 String 默认是使用了上述紧凑的空间布局的,看以下代码,默认将 COMPACT_STRINGS 设置为 true。而若是要取消紧凑的布局能够经过配置 VM 参数-XX:-CompactStrings
实现。ui
static final boolean COMPACT_STRINGS;
static {
COMPACT_STRINGS = true;
}
复制代码
由于改变了 String 的实现,使用了 UTF-16 或 LATIN-1 编码,因此内部须要一个标识coder
来表示使用了哪一种编码,LATIN1 值为0,UTF16 值为1。编码
private final byte coder;
static final byte LATIN1 = 0;
static final byte UTF16 = 1;
复制代码
而字符串的长度也与编码相关,计算时经过右移来实现。若是是 LATIN-1 编码,则右移0位,数组长度即为字符串长度。而若是是 UTF16 编码,则右移1位,数组长度的二分之一为字符串长度。
public int length() {
return value.length >> coder();
}
复制代码
字符串对象是 Java 中大量使用的对象,并且咱们会轻易大量使用它而从不考虑它的代价,因此对其的空间优化是有必要的,Java9 开始对 这能帮助咱们减小字符串在堆中占用的空间,并且还能减轻GC压力。同时也能看到该空间优化对中文来讲意义不大。
-------------推荐阅读------------
跟我交流,向我提问:
公众号的菜单已分为“读书总结”、“分布式”、“机器学习”、“深度学习”、“NLP”、“Java深度”、“Java并发核心”、“JDK源码”、“Tomcat内核”等,可能有一款适合你的胃口。
欢迎关注: