搜索字符串实习和文字字符串声明的成本

REN*_*ENO 6 java performance search string-literals string-interning

两个问题.

  1. 当我们声明文字字符串时,我们搜索堆的字符串池中是否有相同的字符串.这也是一个实习生(课堂实习生String)?

  2. 在我看来,每个文字字符串声明都需要二进制搜索,所以当n是池中现有字符串的数量时,它至少要花费log(n).如果池中有许多字符串,则可能成本很高.(可能需要权衡搜索成本和内存?)从这个角度来看,声明mant文字字符串可能很危险. 这种搜索成本的重要性以及为什么以这种方式设计java(在声明文字字符串时搜索池).

以下是我所提到的理解背景.


该类JavaDocjava.lang.String说明:

字符串是不变的; 它们的值在创建后无法更改.字符串缓冲区支持可变字符串.因为String对象是不可变的,所以可以共享它们.

http://www.janeg.ca/scjp/lang/strLiteral.html评论:

换句话说,因为编译器知道字符串原始值在创建后无法更改,所以它可以安全地使用现有数据并避免使用重复项来弥补内存.

cor*_*iKa 4

您将编译时间复杂性与运行时复杂性混淆了。

当加载类时,是的,它会进行搜索以查看每个文字是否已经存在(尽管我想它会使用哈希图进行 O(1) 查找而不是您的建议)。

当代码运行时,它会引用内存中的字符串,因此与非文字相比没有额外的成本。

所以是的,文字被拘留了。根据 String 的 Javadoc,

字符串池最初是空的,由 String 类私有维护。

您可以调用intern()String 将其添加到此池中。从逻辑上讲, if a.equals(b)then a.intern() == b.intern()、since.intern()保证从唯一池中返回。

例子:

class InternTest {
    // assuming InternTest is the only class, internPool.size = 0
    String x = "ABC"; // interned at class load, internPool.size = 1
    String y = "DEF"; // interned at class load, internPool.size = 2
    String z = "ABC"; // interned at class load, but match found - size = 2 still

    void foo() {
        // random int is just a mechanism to get something that I know won't
        // be interned at loadtime - could have loaded from file or database too
        int i = (new java.util.Random()).nextInt(1000) + 100;
        int j = i;
        String s = String.valueOf(i); // not yet interned, size = 2 still
        String t = String.valueOf(j); // not yet interned, size = 2 still

        String sIntern = s.intern(); // manually interned, size = 3 now
        String tIntern = t.intern(); // manually interned, match found, size = 3 still

        System.out.println("equals: " + (s.equals(t))); // should be true
        System.out.println("== raw: " + (s == t)); // should be false, different variables
        System.out.println("== int: " + (sIntern == tIntern)); // should be true, from unique pool

       System.out.println("x and z: " + (x == z)); // should be true, interned at class load
    }

    public static void main(String[] args) {
        (new InternTest()).foo();
    }

}
Run Code Online (Sandbox Code Playgroud)

运行结果:

C:\Documents and Settings\glowcoder\My Documents>java InternTest
equals: true
== raw: false
== int: true
x and z: true
Run Code Online (Sandbox Code Playgroud)

我应该指出,这个假设永远不会成立。Java 语言本身有许多Strings,在我们String有机会看到曙光之前就已经被实习了。然而,假设所有内容都是按顺序加载的,如果您只考虑被实习生的字符串增量,并假设与现有实习生没有冲突(我们都知道实习生可能很挑剔并且充满戏剧性,对吧?窃笑),那么这些数字确实表明了字符串池大小的增量。

  • 实际上,字符串驻留*确实*发生在运行时(当加载类时)。但每个文字字符串只发生一次,并且复杂度为“O(1)”,因此这不是性能问题。 (2认同)