试图理解Java String实现

时间:2012-08-17 16:21:29

标签: java string size primitive-types

我正在查看String的openjdk实现,并且私有的每个实例成员看起来像:

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence
{
    /** The value is used for character storage. */
    private final char value[];

    /** The offset is the first index of the storage that is used. */
    private final int offset;

    /** The count is the number of characters in the String. */
    private final int count;

    /** Cache the hash code for the string */
    private int hash; // Default to 0

    [...]
}

但我知道Java使用字符串的引用和池,以避免重复。我天真地期待一种流行语成语,其中String实际上只是一个impl的参考。到目前为止我还没有看到。如果我放一个String x,有人可以解释Java如何知道使用引用;我的一个班级的成员?

附录:这可能是错误的,但是如果我处于32位模式,我应该计算:4个字节用于引用“value []”,4个字节用于偏移,4个用于计数,4个用于哈希用于所有实例类String?这意味着写“String x;”在我的一个班级自动添加至少32个字节到我班级的“重量”(我可能在这里错了)。

4 个答案:

答案 0 :(得分:2)

偏移/计数字段与池/ intern()问题有些正交。当你有类似的东西时,会发生偏移和计数:

String substring = myString.substring(5);

实现此方法的一种方法是:

  • 使用char[]元素
  • 分配新的myString.length() - 5
  • 将索引索引5中的所有元素从myString复制到myString.length()到新的char[]
  • substring是使用此新char[]构建的
    • substring.charAt(i)直接转到chars[i]
    • substring.length()直接转到chars.length

如您所见,这种方法是O(N) - 其中N是新字符串的长度 - 并且需要两个分配:新的String和新的char []。因此,substring通过重新使用原始char []来工作,但使用偏移量:

  • substring.offset = myString.offset + newOffset
  • substring.count = myString.count - newOffset
  • 使用myString.chars作为substring的字符数组
    • substring.charAt(i)转到chars[i+substring.offset]
    • substring.length()转到substring.count

请注意,我们不需要创建新的char [],更重要的是,我们不需要将旧的char []中的chars复制到新的char [因为没有新的char]。所以这个操作只是O(1),只需要一个分配,即新String的分配。

答案 1 :(得分:1)

Java 始终使用对任何对象的引用。没有办法让它不使用引用。至于字符串池,这是由编译器为字符串文字实现的,并在运行时通过调用String.intern来实现。很自然地,String的大多数实现都不知道它是否正在处理常量池引用的实例。

答案 2 :(得分:0)

Java字符串是不可变的。这意味着实现可以对内部表示做很多事情,而不会破坏任何应用程序代码。

请注意,Java String.intern()已在Oracle的JDK实现中定义为本机。 本机代码可以访问对象的所有字段,并且可以更改水下的引用。因此,实现者必须做的就是将引用和偏移更改为字符串被插入的位置和瞧。当然这打破了类的不变性,所以这意味着intern()更新更好地是线程安全的。

当您在新生成的字符串上调用intern()时,可以检查字段会发生什么。如果没有任何反应,则可能是引用本身包含内存位置。 Java语言规范没有定义如何实现引用。

答案 3 :(得分:0)

接受的答案和其他答案已过时。在Java 7更新6之后,Java中的字符串不再使用偏移量,也不会针对子字符串优化进行调整。相反,每个子字符串都会创建一个新的字符串副本。

如果您想使用原始字符串实现,则必须使用CharSequence。

有关详细信息:https://jaxenter.com/the-state-of-string-in-java-107508.html