I was having a discussion about usage of String
s and StringBuffer
s in Java. How many objects are created in each of these two examples?
Ex
I've used a memory profiler to get the exact counts.
On my machine, the first example creates 8 objects:
String s = "a";
s = s + "b";
s = s + "c";
String
;StringBuilder
;char[]
.On the other hand, the second example:
StringBuffer sb = new StringBuffer("a");
sb.append("b");
sb.append("c");
creates 2 objects:
StringBuilder
;char[]
.This is using JDK 1.6u30.
P.S. To the make the comparison fair, you probably ought to call sb.toString()
at the end of the second example.
In terms of objects created:
Example 1 creates 8 objects:
String s = "a"; // No object created
s = s + "b"; // 1 StringBuilder/StringBuffer + 1 String + 2 char[] (1 for SB and 1 for String)
s = s + "c"; // 1 StringBuilder/StringBuffer + 1 String + 2 char[] (1 for SB and 1 for String)
Example 2 creates 2 object:
StringBuffer sb = new StringBuffer("a"); // 1 StringBuffer + 1 char[] (in SB)
sb.append("b"); // 0
sb.append("c"); // 0
To be fair, I did not know that new char[] actually created an Object in Java (but I knew they were created). Thanks to aix for pointing that out.
You can determine the answer by analyzing the java bytecode (use javap -c
). Example 1 creates two StringBuilder
objects (see line #4) and two String
objects (see line #7), while example 2 creates one StringBuilder
object (see line #2).
Note that you must also take the char[]
objects into account (since arrays are objects in Java). String
and StringBuilder
objects are both implemented using an underlying char[]
. Thus, example 1 creates eight objects and example 2 creates two objects.
Example 1:
public static void main(java.lang.String[]);
Code:
0: ldc #2; //String a
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 b
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: new #3; //class java/lang/StringBuilder
26: dup
27: invokespecial #4; //Method java/lang/StringBuilder."<init>":()V
30: aload_1
31: invokevirtual #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
34: ldc #8; //String c
36: invokevirtual #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
39: invokevirtual #7; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
42: astore_1
43: return
}
Example 2:
public static void main(java.lang.String[]);
Code:
0: new #2; //class java/lang/StringBuilder
3: dup
4: ldc #3; //String a
6: invokespecial #4; //Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
9: astore_1
10: aload_1
11: ldc #5; //String b
13: invokevirtual #6; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
16: pop
17: aload_1
18: ldc #7; //String c
20: invokevirtual #6; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
23: pop
24: return
}
The answer is tied to specific implementations of the language (compiler and runtime libraries). Even to the presence of specific optimization options or not. And, of course, version of the implementation (and, implicitly, the JLS it is compliant with). So, it's better to speak in term of minima and maxima. In fact, this exercise gives a better
For Ex1, the minimum number of objects is 1 (the compiler realizes that there are only constants involved and produces only code for String s= "abc" ;
). The maximum could be just anything, depending on implementation, but a reasonable estimation is 8 (also given in another answer as the number produced by certain configuration).
For Ex2, the minimum number of objects is 2. The compiler has no way of knowing if we have replaced StringBuilder with a custom version with different semantics, so it will not optimize. The maximum could be around 6, for an extremely memory-conserving StringBuilder implementation that expands a backing char[]
array one character at a time, but in most cases it will be 2 too.