简体   繁体   中英

Java Immutability of Strings, with the “+=” operator

There's plenty of questions about string immutability in Java, for which the author of the question actually re-assigns the reference.

There's however a remarkable case in which it seems there's not a re-assignment of the string:

String s = "hello";
s += " world";

You see that as an actual modification of the string. Try it at home.

I'm pretty sure that this is some kind of syntactic sugar, and gets translated by the compiler in something having the same semantics as:

String s = "hello";
s = s + " world";

Can someone confirm this fact?

Wrong.

x += y is just shorthand for x = x + y .
It's still a regular assignment operation, and it does not modify any existing instances.

I can neither confirm nor deny it. If an optimising compiler could prove to itself that no other thread could "see" the initial (pre- += ) value of s then it would be free to optimise away the concatenation and compile the code to the equivalent of

String s = "hello world";

Compilers have a great deal of freedom as to exactly how they translate from source to bytecode, as long as they obey the memory model.

It is a new object, original object does not get modified;

This:

public static void main(String[] args) {

    String s = "hello";
    s += " world";
    System.out.println(s);

}

Get translated into this:

public static void main(java.lang.String[]);
    Code:
        0: ldc           #2                  // String hello
        2: astore_1
        3: new           #3                  // class java/lang/StringBuilder
        6: dup
        7: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
        10: aload_1
        11: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        14: ldc           #6                  // String  world
        16: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        19: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
        22: astore_1
        23: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
        26: aload_1
        27: invokevirtual #9                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        30: return
}

This creates two String s and adds them into a new String object.

To expand skynorth's answer for those who cannot read Java byte code, given the following source code:

public static void main(String... args) {
    String s = "hello";
    s += "world";
}

When running a JAD decompiler on the compiled class file, you get this Java code:

public static void main(String args[]) {
    String s = "hello";
    s = (new StringBuilder(String.valueOf(s))).append("world").toString();
}

Which is quite self-explanatory and precisely corresponds with the bytecode that skynort posted.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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