简体   繁体   English

字符串池行为

[英]String Pool behavior

I read this Questions about Java's String pool and understand the basic concept of string pool but still don't understand the behavior. 我读了关于Java的字符串池的这个问题并理解了字符串池的基本概念,但仍然不理解这种行为。

First: it works if you directly assign the value and both s1 and s2 refer to the same object in the pool 第一:如果您直接分配值,则它可以工作,并且s1和s2都引用池中的同一对象

String s1 = "a" + "bc";
String s2 = "ab" + "c";
System.out.println("s1 == s2? " + (s1 == s2));

But then if I change the string s1+="d", then the pool should have a string object "abcd"? 但是如果我改变字符串s1 + =“d”,那么池应该有一个字符串对象“abcd”? then when I change the s2+="d", it should find the string object "abcd" in the pool and should assign the object to s2? 那么当我更改s2 + =“d”时,它应该在池中找到字符串对象“abcd”,并将对象分配给s2? but it doesn't and they aren't referred to the same object. 但它没有,它们不会被引用到同一个对象。 WHY is that? 这是为什么?

String s1 = "abc";
String s2 = "abc";
System.out.println("s1 == s2? " + (s1 == s2));

s1 += "d";                  
s2 += "d";
System.out.println("s1 == s2? " + (s1 == s2));

Strings are guaranteed to be pooled when you call String.intern() on a string. 当您在字符串上调用String.intern()时,可以保证字符串是池化的。

String s1 = "abcd".intern();
String s2 = "abc";
s2 += "d";
s2 = s2.intern();
s1 == s2 // returns true

When compiler sees a constant it's smart enough to optimize and pool the string literal, ie: 当编译器看到一个常量时,它足够智能来优化和汇集字符串文字,即:

String s1 = "abcd";
String s2 = "abcd";
s1 == s2 // returns true

Java Language Specification states: Java语言规范声明:

Each string literal is a reference (§4.3) to an instance (§4.3.1, §12.5) of class String (§4.3.3). 每个字符串文字都是类String(第4.3.3节)的实例(第4.3.1节,第12.5节)的引用(第4.3节)。 String objects have a constant value. String对象具有常量值。 String literals-or, more generally, strings that are the values of constant expressions (§15.28)-are "interned" so as to share unique instances, using the method String.intern. 字符串文字 - 或者更一般地说,作为常量表达式(第15.28节)的值的字符串 - 是“实例化”以便使用String.intern方法共享唯一实例。

So in the case of s2 += "d" , compiler wasn't as clever as you are and just pooled "d" . 所以在s2 += "d"的情况下,编译器并不像你那样聪明,只是汇集了"d"

I'm not sure about this, so this is pretty much speculation, but I suspect that there may be some compiler trickery going on in the first example (where it's inline and pretty obvious what's going on), but it's not clever enough to pull it off in the second example (where it's not so obvious). 我不确定这一点,所以这几乎是猜测,但我怀疑在第一个例子中可能会有一些编译器技巧(它是内联的,非常明显的是发生了什么),但它并不够聪明。它在第二个例子中(它不是那么明显)。

If I'm right, either the compiler sees "a" + "bc" and simply compresses that down at compile time to "abc" or it's seeing the two lines and pooling the strings because it realizes they will be used. 如果我是对的,要么编译器看到"a" + "bc"并且只是在编译时将其压缩为"abc"或者它看到两行并汇集字符串,因为它意识到它们将被使用。 I'm betting on the former.. 我打赌前者..

Not all strings necessarily get pooled. 并非所有字符串都必须汇总。

See the documentation for String#intern() . 请参阅String #intern()的文档。 The last line there states: 最后一行指出:

All literal strings and string-valued constant expressions are interned. 所有文字字符串和字符串值常量表达式都是实体。

Your += example is neither a literal string nor a string-valued constant expression, so it is not put in the String pool. 您的+=示例既不是文字字符串也不是字符串值常量表达式,因此它不会放在字符串池中。

The compiler can perform constant evaluation but not in the case where you modify the values 编译器可以执行常量求值,但不能在修改值的情况下执行

Try instead following and see what happens if you drop final from either variable. 请尝试关注并查看如果从任一变量中删除final会发生什么。

final String s1 = "abc";
final String s2 = "abc";
System.out.println("s1 == s2? " + (s1 == s2));

String s3 = s1 + "d";                  
String s4 = s2 + "d";
System.out.println("s3 == s4? " + (s3 == s4));

This is my guess: 这是我的猜测:

String s1 = "a" + "bc"; String s1 =“a”+“bc”; String s2 = "ab" + "c"; 字符串s2 =“ab”+“c”;

I think that are compile time these are determined to produce the same string and so only one object is made for both. 我认为这是编译时间,这些是确定生成相同的字符串,因此只有一个对象。

But when you add "d" to both of them, this is done separately for both strings (since it's done during real time, there could be things like exceptions interrupting it etc, so it can't pre-do it) and so it doesn't automatically make them reference one object. 但是当你向他们两个添加“d”时,这是针对两个字符串单独完成的(因为它是在实时完成的,可能会有异常中断它等等,所以它不能预先做它)所以它不会自动使它们引用一个对象。

I think what happens here is: 1. for String s1 = "a" + "bc"; 我想这里发生的是:1。对于String s1 =“a”+“bc”; String s2 = "ab" + "c"; 字符串s2 =“ab”+“c”; Java compiler is smart enough to know that the literal value of s1 and s2 are the same, so the compiler points them to the same literal value in the string pool Java编译器足够聪明,知道s1和s2的文字值是相同的,因此编译器将它们指向字符串池中的相同文字值

  1. for s1 += "d"; 对于s1 + =“d”;
    s2 += "d"; s2 + =“d”;

there is no way the compiler know if s1 and s2 would end up being the same value, At runtime, unless you call String.intern(), jvm won't check the string literal pool to see if the value is already there. 编译器无法知道s1和s2是否会最终成为相同的值。在运行时,除非调用String.intern(),否则jvm将不检查字符串文字池以查看该值是否已存在。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM