When does the pool change?

2020-01-27 07:44发布

问题:

I have two questions:

public static void main(String[] args) {
  String s1 = "bla";
  String s2 = "b" +"l" + "a";
  String s3 = "b".concat("l").concat("a");

  if(s1 == s2) 
        System.out.println("Equal");
  else
        System.out.println("Not equal");
  if(s1 == s3) 
        System.out.println("Equal");
  else
        System.out.println("Not equal");
}
  • Why does s1 and s2 point to the same object, whereas s1 and s3 doesn't? (There is no usage of new keyword).

  • If I get a string from the user and add to the above code these lines:

    BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
    String name=in.readLine();
    if(name.equals("test"))
        s1 = s1 + "xyz";
    

    If the user enters xyz the program will print Not equal, when the user enters another thing the program outputs Equal. Does this mean that the pool changes through the execution of the whole program? Does the optimizer works at the compile time and continues to work in the runtime?

回答1:

Why does s1 and s2 point to the same object, whereas s1 and s3 doesn't? (There is no usage of new keyword).

Because the concatenation happens at compile time, and the completed string therefore goes in the constant pool the same as in the first example. It's a special case "known" to the compiler. It's really meant so that long strings, concatenated this way over several lines, still get the benefit of the same performance improvements as simple string constants.

In the second example, you're performing the calculation at runtime, so it won't be part of the constant pool.

Note however that in the JLS the details of what can and can't go in the string constant pool is deliberately left vague, so different implementations may optimise in different ways. It specifies certain rules as to what has to go in there, but don't rely on this behaviour being consistent across implementations.



回答2:

Why does s1 and s2 point to the same object, whereas s1 and s3 doesn't? (There is no usage of new keyword).

Since String in Java are Immutable, so any method of string class will return a new String object (there are some exception though - one is substring method). Hence concat method creates a new string, that goes to the Heap, and is not added to constant pool.

As far as the case of s1 and s2 is concerned, both strings are known at compile time, and hence they are same string literals.

Note that the concatenation operation in 2nd string: -

String s2 = "b" +"l" + "a";

is evaluated at compile time, and the result is known to be same as the first string, and one entry is made to the constant pool.



回答3:

Sometimes (when it is evident for the compiler what the value of a String will be at runtime) compiler uses String pool, in other cases it doesn't.

Actually your code should not depend on the fact of using or not using the pool.

You cannot always run main, so if you want to see if your String is used from the pool, you can decompile the code with javap the listing is relatively self-explanatory.



标签: java string pool