Java 9 中的紧凑字符串和示例
先决条件:字符串
Compact String是 JVM 中作为 JDK 9 的一部分引入的性能增强之一。直到 JDK 8,每当我们创建一个 String 对象时,它在内部都表示为 char[],它由 String 对象的字符组成。
Compact String 需要什么?
- 直到 JDK 8, Java将 String 对象表示为 char[],因为Java中的每个字符都是 2 个字节,因为Java内部使用 UTF-16。
- 如果任何 String 包含英语单词,则该字符只能使用单个字节表示,每个字符不需要 2 个字节。许多字符需要 2 个字节来表示它们,但大多数字符只需要 1 个字节,属于 LATIN-1字符集。因此,存在改善内存消耗和性能的空间。
- Java 9 引入了紧凑字符串的概念。紧凑字符串的主要目的是每当我们创建一个字符串对象并且对象内部的字符可以用 1 个字节表示,这不过是 LATIN-1 表示,然后在内部Java将创建一个字节[]。在其他情况下,如果任何字符需要超过 1 个字节来表示它,则每个字符都使用 2 个字节存储,即 UTF-16 表示。
- 这就是Java开发人员如何改变String的内部实现,即所谓的Compact String,这将改善String的内存消耗和性能。
Java 9 之前的 String 类内部实现:
Java 8 or before
import java.io.Serializable;
public final class String
implements Serializable,
Comparable,
CharSequence {
// The value is used
// for character storage.
private final char value[];
}
Java 9 and after
import java.io.Serializable;
public final class String
implements Serializable,
Comparable,
CharSequence {
private final byte[] value;
private final byte coder;
}
注意:在上面的程序中,我们可以看到在Java 9 之前, Java仅将 String 对象表示为 char[]。假设我们创建一个 String 对象,并且对象包含可以用 1 个字节表示的字符。它不会将对象表示为 byte[],而是仅创建 char[],这将消耗更多内存。
JDK 开发人员分析,大多数字符串只能使用Latin-1字符集来表示。 Latin-1 char 可以存储在一个字节中,正好是 char 大小的一半。这将提高 String 的性能。
Java 9 中的字符串类内部实现
Java 9 及更高版本
import java.io.Serializable;
public final class String
implements Serializable,
Comparable,
CharSequence {
private final byte[] value;
private final byte coder;
}
注意:现在的问题是它如何区分LATIN-1和UTF-16表示? Java开发人员引入了一种最终字节变量编码器,它保留了有关字符表示的信息。 coder value 的值可以是:
static final byte LATIN1 = 0;
static final byte UTF16 = 1;
因此, Java 9 中称为 Compact String 的新 String 实现在性能方面优于Java 9 之前的 String,因为与 JDK 9 的堆中的 String 相比,Compact String 使用了大约一半的区域。
让我们看看Java 9 之前和Java 9 之前 String 对象使用的内存的区别:
// Program to illustrate the memory
// used by String before Java 9
public class Geeks {
public static void main(String[] args)
{
String s
= new String("Geeksforgeeks");
}
}
当我们在Java 8 或更早版本上运行时需要注意的要点:
- 在这里,我们创建了一个包含 13 个字符的 String 对象,对象内部的字符可以用 1 个字节表示,这不过是 LATIN-1 表示。
- 如果我们使用 JDK 8 或更早版本运行上述程序,那么由于 JDK 8 默认使用 UTF-16,内部字符串将表示为 char[]。
- 这里我们不需要 char[],我们可以只用 1 个字节来表示每个字符。将创建 char[] 而不是创建 byte[],并且对于每个字符,在堆内存中分配 2 个字节。这不过是堆内存的浪费。
// Program to illustrate the memory
// used by String from Java 9
public class Geeks {
public static void main(String[] args)
{
String s1 = new String("Geeksforgeeks");
String s2 = new String("Geeksforgeeks€");
}
}
在Java 9 上运行时需要注意的要点:
- 从Java 9 开始,将根据需要为 String 对象创建 char[] 或 byte[]。在这里我们可以看到我们创建了具有 13 个字符的字符串对象 s1 和具有 14 个字符的对象 s2。
- 对象 s1 中存在的每个字符只能使用 1 个字节来表示。这就是为什么对于对象 s1,将创建一个 byte[]。
- 现在对于 s2,除了对象 s1 中存在的字符之外,我们还有一个额外的字符,即 €。我们不能使用 LATIN-1字符集来表示 €字符。这里我们需要 2 个字节来表示 €。这就是为什么这里Java将使用 UTF-16 来呈现 s2 中表示的字符。
- 对于对象 s2,将在内部创建 char[]。
- 这就是Java 9 中称为 Compact String 的新 String 实现在内存消耗和性能方面优于Java 9 之前的 String 的原因。