How many String objects will be created

混江龙づ霸主 提交于 2019-11-26 16:42:25

"Fred" and "47" will come from the string literal pool. As such they won't be created when the method is invoked. Instead they will be put there when the class is loaded (or earlier, if other classes use constants with the same value).

"Fred47", "ed4" and "ED4" are the 3 String objects that will be created on each method invocation.

Programs tend to contain a lot of String literals in their code. In Java, these constants are collected in something called the string table for efficiency. For instance, if you use the string "Name: " in ten different places, the JVM (typically) has just one instance of that String and in all ten places where it's used, the references all point to that one instance. This saves memory.

This optimization is possible because String is immutable. If it were possible to change a String, changing it one place would mean it changes in the other nine as well. That's why any operation that changes a String returns a new instance. That's why if you do this:

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

it prints boink, not BOINK.

Now there's one more tricky bit: multiple instances of java.lang.String may point to the same underlying char[] for their character data, in other words, they may be different views on the same char[], by using just a slice of the array. Again, an optimization for efficiency. The substring() method is one of the cases where 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, all this boils down to:

  • The string "Fred" is taken from the String table.
  • The string "47" is taken from the String table.
  • The string "Fred47" is created during the method call. //1
  • The string "ed4" is created during the method call, sharing the same backing array as "Fred47" //2
  • The string "ED4" is created during the method call. //3
  • The s.toString() doesn't create a new one, it just returns this.

One interesting edge case of all this: consider what happens if you have a really long String, for example, a web page taken from the Internet, let's say the length of the char[] is two megabytes. If you take the substring(0, 4) of this, you get a new String that looks like it's just four characters long, but it still shares those two megabytes of backing data. This isn't all that common in the real world, but it can be a huge waste of memory! In the (rare) case that you run into this as a problem, you can use new String(hugeString.substring(0, 4)) to create a String with new, small backing array.

Finally, it's possible to force a String into the string table at runtime by calling intern() on it. The basic rule in this case: don't do it. The extended rule: don't do it unless you've used a memory profiler to ascertain that it's a useful optimization.

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

The last call is not redundant because it transforms the StringBuilder into 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

}

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!