1

There are many questions on this in many forums but when you read every one of them, you actually go back to where you started!! As far as I've understood, for the example below:

1. String s = "abc" + "xyz"; 

...will create 3 objects right? "abc"(which is lost as no reference is assigned), "xyz"(lost) and "abcxyz"

2. String s = new String("def"); 

...will create 2 string objects. "def" and the one with the new operator

For 1, I hear that compile time resolves the string concatenation and only 1 object "abcxyz" gets created

For 2, I hear that when we use new, sometimes char[] containing its data is created which adds to the number of objects created!!

Please let me know if this is right.

Gajanan Kulkarni
  • 697
  • 6
  • 22
Mercenary
  • 2,106
  • 6
  • 34
  • 43

3 Answers3

1

You are getting lost in implementation details. Clearly, you want to understand, but I suggest that you get a really good grasp of Objects first.

If you stick to the basics, then 1. has just one object, s, and two literals; 2. has just one object, s.

Implementation details can (and do) change. Deep concepts are much more stable.

andy256
  • 2,821
  • 2
  • 13
  • 19
  • Thanks. Does this mean that when we say literals, it is just that string instances are created that go to string pool and when a new operator comes, that is when string objects are created? – Mercenary Jul 17 '13 at 05:18
  • Conceptually, yes. But the compiler and the JVM can do optimizations; this is why I say to just concentrate on the concepts first. – andy256 Jul 17 '13 at 05:33
  • 1
    I do not believe that I can agree that item 1 has "just 1 object". The String literals can be and usually are implemented as cached final static objects on the heap. If they weren't, how would you be able to locate references to them and pass them around? Also, I think a distinction needs to be made between an object (i.e. a data structure for which memory has been allocated on the heap) and a reference variable (which is held on the stack). It's not the most correct to regard "s" as an object; it is a variable that is holding a reference to a String object somewhere on the heap. – scottb Jul 17 '13 at 06:02
1
String s = "abc" + "xyz"; 

If the concatenation is a compile-time constant expression, it will be performed by the compiler, and the resulting String is added to the String pool . Refer JLS 3.10.5

long string literal can always be broken up into shorter pieces and written as a (possibly parenthesized) expression using the string concatenation operator + [...] Moreover, a string literal always refers to the same instance of class String.

-Strings computed by constant expressions (§15.28) are computed at compile time and then treated as if they were literals.

-Strings computed by concatenation at run-time are newly created and therefore distinct.

The string concatenation operator + (§15.18.1) implicitly creates a new String object when the result is not a compile-time constant expression (§15.28).

String s = new String("def"); 

I am not sure but it seems intern() is used here.The JVM forces first to search any string literal is there in internal pool or not, if it there then it will create a new String object with same character sequence or else it will create an object in the pool and another object in the heap.

AllTooSir
  • 48,828
  • 16
  • 130
  • 164
1

If you want to see exactly what the compiler produces, dump out the bytecode from the .class file with the javap command:

$ cat Foo.java
public class Foo {
    public String one() {
        String s = "abc" + "xyz";
        return s;
    }

    public String two() {
        String s = new String("def");
        return s;
    }
}
$ javac Foo.java
$ javap -verbose Foo.class
Classfile /Users/andrew/projects/sx/17690890/Foo.class
  Last modified 16-Jul-2013; size 393 bytes
  MD5 checksum d5818f15e34097180729ce7c3055594e
  Compiled from "Foo.java"
public class Foo
  SourceFile: "Foo.java"
  minor version: 0
  major version: 51
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #7.#17         //  java/lang/Object."<init>":()V
   #2 = String             #18            //  abcxyz
   #3 = Class              #19            //  java/lang/String
   #4 = String             #20            //  def
   #5 = Methodref          #3.#21         //  java/lang/String."<init>":(Ljava/lang/String;)V
   #6 = Class              #22            //  Foo
   #7 = Class              #23            //  java/lang/Object
   #8 = Utf8               <init>
   #9 = Utf8               ()V
  #10 = Utf8               Code
  #11 = Utf8               LineNumberTable
  #12 = Utf8               one
  #13 = Utf8               ()Ljava/lang/String;
  #14 = Utf8               two
  #15 = Utf8               SourceFile
  #16 = Utf8               Foo.java
  #17 = NameAndType        #8:#9          //  "<init>":()V
  #18 = Utf8               abcxyz
  #19 = Utf8               java/lang/String
  #20 = Utf8               def
  #21 = NameAndType        #8:#24         //  "<init>":(Ljava/lang/String;)V
  #22 = Utf8               Foo
  #23 = Utf8               java/lang/Object
  #24 = Utf8               (Ljava/lang/String;)V
{
  public Foo();
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0       
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return        
      LineNumberTable:
        line 1: 0

  public java.lang.String one();
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=2, args_size=1
         0: ldc           #2                  // String abcxyz
         2: astore_1      
         3: aload_1       
         4: areturn       
      LineNumberTable:
        line 3: 0
        line 4: 3

  public java.lang.String two();
    flags: ACC_PUBLIC
    Code:
      stack=3, locals=2, args_size=1
         0: new           #3                  // class java/lang/String
         3: dup           
         4: ldc           #4                  // String def
         6: invokespecial #5                  // Method java/lang/String."<init>":(Ljava/lang/String;)V
         9: astore_1      
        10: aload_1       
        11: areturn       
      LineNumberTable:
        line 8: 0
        line 9: 10
}

Hopefully you know a bit of assembly so that this makes more sense. You can read more details about the bytecode instructions on Wikipedia.

What’s going on is:

  1. In the first example, the compiler optimizes the concatenation of two constant strings at compile time. The concatenated string "abcxyz" is stored in the class file’s “constant pool” as String #2 which references the text constant #18. All the one() method does is return the constant string. The object is automatically created when the class is loaded, and since strings are immutable, no additional objects are ever created, no matter how many times you call the one() method. So the answer in this special case is that zero objects get created each time that line of code executes.

  2. In the second example, each time the line gets executed, one new String object is explicitly created and the String() constructor is explicitly called. However, the "def" argument to the constructor comes from the constant pool, which is read-only memory created when the class is loaded, so no additional char[] object is created. The JLS requires that new creates a fresh object so I don’t think the JVM can optimize the object creation away.

andrewdotn
  • 32,721
  • 10
  • 101
  • 130
  • +1 For the explanation. But for 2 are not all String objects created as char[] Arrays ? For eg : If you take a heap dump of this running program it will show two objects for 2 also. One a char[] and one String. – Geek Jul 17 '13 at 05:56
  • +1 for the explanation. So, do you mean that when any line which says : `String s = "abc"` so this means no string objects are created on heap. Instead, abc is just put in string pool. And, when `String s = new String("abc")` is used, how is "def" coming from the String pool if the line is called for the first time? – Mercenary Jul 17 '13 at 10:48
  • Just to add to #1, from the link, it is mentioned that string literals are stored in the string pool during compile time and when the class is loaded, string objects are created. [http://stackoverflow.com/questions/8046045/java-string-literal-pool-and-string-object] – Mercenary Jul 17 '13 at 11:50