How many String objects will be created

I have the following Java code:

public String makinStrings() { String s = "Fred"; s = s + "47"; s = s.substring(2, 5); s = s.toUpperCase(); return s.toString(); } 

The question is somehow simple: how many String objects will be created when this method is called?

At the beginning, I replied that 5 String objects were created, but the answer from my book says that only 3 objects were created, and there were no explanations (this is an SCJP question).

From my point of view, there are 5 objects: "Fred", "47", "Fred47", "ed4", "ED4".

I also found this question on an SCJP simulation exam with the same answer 3.

+6
source share
3 answers

Fred and 47 will come from a pool of string literals. Therefore, they will not be created when the method is called. Instead, they will be placed there when the class is loaded (or earlier if other classes use constants with the same value).

"Fred47", "ed4" and "ED4" are 3 String objects that will be created each time the method is called.

+15
source

Programs typically contain many string literals in their code. In Java, these constants are compiled for something called a row table for efficiency. For example, if you use the string "Name: " in ten different places, the JVM (usually) has only one instance of this line and in all ten places where it is used, all links point to one instance. It saves memory.

This optimization is possible because String is immutable. If it were possible to change the line by changing it, one place would mean its change in the other nine. Therefore, any operation that changes the string returns a new instance. Therefore, if you do this:

 String s = "boink"; s.toUpperCase(); System.out.println(s); 

he prints boink , not boink .

Now there is one more difficult bit: several instances of java.lang.String can point to the same base char[] for their character data, in other words, they can be different representations on the same char[] , using only an array slice. Again, optimization of efficiency. The substring() method is one of the cases when this happens.

 s1 = "Fred47"; //String s1: data=[ 'F', 'r', 'e', 'd', '4', '7'], offset=0, length=6 // ^........................^ s2 = s1.substring(2, 5); //String s2: data=[ 'F', 'r', 'e', 'd', '4', '7'], offset=2, length=3 // ^.........^ // the two strings are sharing the same char[]! 

In your SCJP question, it all boils down to:

  • The string "Fred" taken from the String table.
  • Row "47" taken from the String table.
  • The string "Fred47" is created during a method call. // 1
  • The string "ed4" is created during the method call, using the same support array as "Fred47" // 2
  • When the method is called, the line "ed4" created .//3
  • s.toString() does not create a new one, it just returns this .

One interesting marginal case of everything: think about what happens if you have a really long line, for example, a web page taken from the Internet, let char[] be two megabytes in length. If you take the substring(0, 4) this, you get a new String that looks like four characters long, but it still shares the two megabytes of backup data. This is not all that is common in the real world, but it can be a huge waste of memory! In the rare case when you come across this as a problem, you can use new String(hugeString.substring(0, 4)) to create a String with a new small support array.

Finally, you can force a row into the row table at run time by calling intern() on it. The basic rule in this case: do not do this. Extended Rule: Do not do this unless you have used a memory profiler to make sure that this is a useful optimization.

+2
source

Based on javap output, it looks like a StringBuilder is created during concatentation, not a String. There are three lines called substring (), toUpperCase () and toString ().

The last call is not redundant because it converts the StringBuilder to a string.

 >javap -c Test Compiled from "Test.java" public java.lang.String makinStrings(); Code: 0: ldc #5; //String Fred 2: astore_1 3: new #6; //class java/lang/StringBuilder 6: dup 7: invokespecial #7; //Method java/lang/StringBuilder."<init>":()V 10: aload_1 11: invokevirtual #8; //Method java/lang/StringBuilder.append: (Ljava/lang/String;)Ljava/lang/StringBuilder; 14: ldc #9; //String 47 16: invokevirtual #8; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 19: invokevirtual #10; //Method java/lang/StringBuilder.toString:()Ljava/lang/String; 22: astore_1 23: aload_1 24: iconst_2 25: iconst_5 26: invokevirtual #11; //Method java/lang/String.substring:(II)Ljava/lang/String; 29: astore_1 30: aload_1 31: invokevirtual #12; //Method java/lang/String.toUpperCase:()Ljava/lang/String; 34: astore_1 35: aload_1 36: invokevirtual #13; //Method java/lang/String.toString:()Ljava/lang/String; 39: areturn 

}

+2
source

Source: https://habr.com/ru/post/897036/


All Articles