How many strings are created in the codes below?

8

How many String s does the JVM actually create during the runtime of the code snippets below?

1 :

String s1 = "s1";

2 :

String s2 = new String("s2");

3 :

String s3 = "s3";
String s4 = s3 + "s4";

4 :

String s5 = "s5";
String s6 = s5 + "-" + "s6";

5 :

final String s7 = "s7";
String s8 = s7 + "s8";

6 :

final String s9 = "s9";
String s10 = s9 + "-" + "s10";
    
asked by anonymous 21.02.2017 / 18:17

4 answers

7

It's not a complete answer, but it gives you an idea.

I've compiled the following class with javac 1.8.0_111:

public class Teste {
    public String x() {
        String s1 = "s1";

        String s2 = new String("s2");

        String s3 = "s3";
        String s4 = s3 + "s4";

        String s5 = "s5";
        String s6 = s5 + "-" + "s6";

        final String s7 = "s7";
        String s8 = s7 + "s8";

        final String s9 = "s9";
        String s10 = s9 + "-" + "s10";

        return s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10;
    }
}

And I decompiled the result:

/*
 * Decompiled with CFR 0_118.
 */
public class Teste {
    public String x() {
        String string = "s1";
        String string2 = new String("s2");
        String string3 = "s3";
        String string4 = string3 + "s4";
        String string5 = "s5";
        String string6 = string5 + "-s6";
        String string7 = "s7s8";
        String string8 = "s9-s10";
        return string + string2 + string3 + string4 + string5 + string6 + "s7" + string7 + "s9" + string8;
    }
}

Using another decompiler:

// 
// Decompiled by Procyon v0.5.30
// 

public class Teste
{
    public String x() {
        final String s = "s1";
        final String s2 = new String("s2");
        final String s3 = "s3";
        final String string = s3 + "s4";
        final String s4 = "s5";
        return s + s2 + s3 + string + s4 + (s4 + "-s6") + "s7" + "s7s8" + "s9" + "s9-s10";
    }
}

Note that the compiler was clever and has already done some of the concatenations by itself, and therefore the result will not always be obvious. However, clearly, he could be even smarter than he is.

I tried to make a variant by removing the final modifiers, believing it would not make any difference. To my surprise, final made a difference yes. Here are the results of decompiling:

/*
 * Decompiled with CFR 0_118.
 */
public class Teste2 {
    public String x() {
        String string = "s1";
        String string2 = new String("s2");
        String string3 = "s3";
        String string4 = string3 + "s4";
        String string5 = "s5";
        String string6 = string5 + "-s6";
        String string7 = "s7";
        String string8 = string7 + "s8";
        String string9 = "s9";
        String string10 = string9 + "-s10";
        return string + string2 + string3 + string4 + string5 + string6 + string7 + string8 + string9 + string10;
    }
}
// 
// Decompiled by Procyon v0.5.30
// 

public class Teste2
{
    public String x() {
        final String s = "s1";
        final String s2 = new String("s2");
        final String s3 = "s3";
        final String string = s3 + "s4";
        final String s4 = "s5";
        final String string2 = s4 + "-s6";
        final String s5 = "s7";
        final String string3 = s5 + "s8";
        final String s6 = "s9";
        return s + s2 + s3 + string + s4 + string2 + s5 + string3 + s6 + (s6 + "-s10");
    }
}

I also tried another variant, putting final on all variables:

/*
 * Decompiled with CFR 0_118.
 */
public class Teste3 {
    public String x() {
        String string = new String("s2");
        return "s1" + string + "s3" + "s3s4" + "s5" + "s5-s6" + "s7" + "s7s8" + "s9" + "s9-s10";
    }
}
// 
// Decompiled by Procyon v0.5.30
// 

public class Teste3
{
    public String x() {
        return "s1" + new String("s2") + "s3" + "s3s4" + "s5" + "s5-s6" + "s7" + "s7s8" + "s9" + "s9-s10";
    }
}

That is, the code with final compiles better.

    
21.02.2017 / 20:32
3

I will give an alternative answer because either the question is tricky, or it has been poorly worded.

The question talks about runtime creation. So do not count the ones that have already been created at compile time, right?

Depends on the implementation of the used JVM and Java compiler. There may or may not be optimizations in some cases. Other optimization is certainly not possible, or it is only possible if done aggressively.

The language specification does not determine exactly how the runtime should proceed in several of these cases.

Our question here has the tag Java, but in the text it does not talk about Java, just about JVM. By the syntax it is unlikely that it could be another language, but could, what could otherwise.

    
21.02.2017 / 20:08
3

In total, along the proposed code, 16 Strings are created, as comments added:

1 :

String s1 = "s1"; // Objeto 1 colocado no Pool

2 :

String s2 = new String("s2"); // Objeto 2 e 3, um literal (que vai para o Pool) e outro com o new

3 :

String s3 = "s3"; // Objeto 4 colocado na Pool
String s4 = s3 + "s4"; // Objeto 5 não colocado no Pool s4 E Objeto 6 "s4"

4 :

String s5 = "s5"; // Objeto 7 colocado no Pool
String s6 = s5 + "-" + "s6"; // Objeto 8 não colocado no Pool s6 e Objeto 9 ("-") colocado no Pool e Objeto 10 "s6"

5 :

final String s7 = "s7"; // Objeto 11 colocado no Pool
String s8 = s7 + "s8"; // Objeto 12 não colocado no Pool e Objeto 13 "s8"

6 :

final String s9 = "s9"; // Objeto 14 colocado no Pool
String s10 = s9 + "-" + "s10"; // Objeto 15 não colocado no Pool (reutiliza Objeto 9 do pool) e Objeto 16 "s10"

Strings Pool

Java has a pool of objects of type String. Before creating a new String, it first checks in this pool whether a String with the same content already exists; In this case, it reuses it, avoiding creating exactly two objects in memory.

It's important to note that Java just puts Strings created using literals into the pool. Strings created with the new operator are not placed in the pool automatically. Another important point is that the resulting strings of literal concatenations are also placed in the pool. But this only occurs when there are literals on both sides of the concatenation. If any of the objects is not a literal, the result will be a new object, outside the pool.

    
21.02.2017 / 19:36
0

First, the compiler will already create the String , "s1" , "s2" , "s3" , "s4" , "s5" , "-s6" , "s7" , "s8" and "s9" and these will be present in the generated bytecode and "-s10" s pool during execution. The compiler is smart enough to convert String to "-" + "s6" and "-s6" to "-" + "s10" (at least javac 1.8.0_111 is).

So, we've already started with these 10 "-s10" s.

// 1. Apenas aponta para uma String já existente no pool.
String s1 = "s1";

// 2. Cria uma nova String: "s2".
String s2 = new String("s2");

// 3a. Apenas aponta para uma String já existente.
String s3 = "s3";

// 3b. Cria uma nova String: s4 = "s3s4"
String s4 = s3 + "s4";

// 4a. Apenas aponta para uma String já existente.
String s5 = "s5";

// 4b. Cria uma nova String: s5 = "s5-s6"
String s6 = s5 + "-" + "s6";

// 5a. Apenas aponta para uma String já existente.
final String s7 = "s7";

// 5b. Cria uma nova String: s8 = "s7s8"
String s8 = s7 + "s8";

// 6a. Apenas aponta para uma String já existente.
final String s9 = "s9";

// 6b. Cria uma nova String: s10 = "s9-s10"
String s10 = s9 + "-" + "s10";

In addition to the 10% with% s originally present that were in the bytecode, a further 5% with% s were created in steps 2, 3b, 4b, 5b and 6b.     

21.02.2017 / 20:17