How many string objects in Java? [duplicate]
Asked Answered
T

3

38

My friend sent me a question he saw in one mock exam for the Java certification about string objects:

String makeStrings(){
    String s = "HI";
    s = s + "5";
    s = s.substring(0,1);
    s = s.toLowerCase();
    return s.toString();
}

How many string objects will be created when this method is invoked? The correct answer the exam gave was 3. But I think it's five.

  1. "HI"
  2. "5"
  3. "HI5"
  4. "H"
  5. "h"

Am I wrong?

Timothee answered 27/7, 2013 at 13:17 Comment(10)
I suspect the difference is that "HI" and "5" are already in the string pool, so they're not created on each method invocation.Spirograph
@GrijeshChauhan I made a post on SO meta. Instead of closing this post, I think we should vote to close the other one. Perhaps I'm biased, but I think these answers are better...Slope
@SteveP. I voted it to close already with duplicate option...Shinleaf
This should be reopened and the other one should be marked as a duplicate. The answers in this question are more explanatory...Slope
@EJP I don't think that it's a duplicate of that question. Nonetheless, some redundancy between questions should be expected. It's not necessarily a bad thing to have marginally different questions and keep them both open...Slope
Looks like 3 to me, "HI5", "H", "h". "HI" and "5" are constants, so a new string isn't created for those in this method.Sulfate
@SteveP. These questions may have different preconditions and different numerical answers, but the underlying answer is always the same: the string literals and compile-time concatenations don't create new objects; the new String() calls do. Unless you think it is desirable to have a separate question every time the preconditions or the numerical answer is different, e.g. 1,2,3,4,5,... ad infinitum I really cannot see the point of your comment.Freightage
@EJP Well, the other questions don't contain anything about substring(), toLowerCase() and toString()` is what I meant.Slope
Again, I can't vote to reopen again, but it's overtly obvious that this is not a duplicate question. In fact the other question is a subset of this question. This question includes substring(),toLowerCase(), and toString() which the other question does not include. I do not know why this was closed...Slope
Don't forget that String is typically two objects, not one. There is the String and the char[] (possibly a byte[]) that it wraps.Everara
S
46
String makeStrings() {
    String s = "HI";           //String literal
    s = s + "5";               //concatenation creates new String object (1)
    s = s.substring(0,1);      //creates new String object (2)
    s = s.toLowerCase();       //creates new String object (3)
    return s.toString();       //returns already defined String
}

With respect to the concatenation, when creating a new String,JVM uses StringBuilder, ie:

s = new StringBuilder(s).append("5").toString(); 

toString() for a StringBuilder is:

public String toString() {
    return new String(value, 0, count); //so a new String is created
}

substring creates a new String object unless the entire String is indexed:

public String substring(int beginIndex, int endIndex) {
    if (beginIndex < 0) {
        throw new StringIndexOutOfBoundsException(beginIndex);
    }
    if (endIndex > count) {
        throw new StringIndexOutOfBoundsException(endIndex);
    }
    if (beginIndex > endIndex) {
        throw new StringIndexOutOfBoundsException(endIndex - beginIndex)
    }

    return ((beginIndex == 0) && (endIndex == count)) ? this :
           new String(offset + beginIndex, endIndex - beginIndex, value);
}

toString() does NOT create a new String:

public String toString()
{
   return this;
}

toLowerCase() is a pretty long method, but suffice it to say that if the String is not already in all lowercase, it will return a new String.

Given that the provided answer is 3, as Jon Skeet suggested, we can assume that both of the String literals are already in the String pool. For more information about when Strings are added to the pool, see Questions about Java's String pool.

Slope answered 27/7, 2013 at 13:21 Comment(8)
Substring creates a new string object, toString doesn'tMilissamilissent
substring will create an object here. It returns the same string only when your indices are at boundaries of original string - [0, s.length() - 1]Suburban
@Joni, I didn't realize that it was actually calling toString() on a String. I made the necessary changes (for both). Thank you.Slope
With your explanation, I see 4 strings created, instead of 3, as the asker said: string literal, concatenation, substring and toLowerCase.Synesthesia
@guillegr123 Given that the answer provided by the OP was 3, one can deduce that the string literal was already added to the String pool.Slope
@SteveP. i just accepted it, but i dont understand why the "5" isnt considered a new String object, theres nothing more to the question than what i posted, how can i assume that the 5 is already in the pool?Timothee
@MauroMazzucco Thank you. You can't for no reason assume that it's already in the pool; however, since the answer provided was 3, we CAN assume that the String was already in the pool--it's the only way the answer makes sense.Slope
From Java 7 onwards, Strings are only added to the String literal pool as they are used for the first time. While your answer is correct for earlier versions if you ignore the Strings added to the String literal pool, that is a big assumption. Your answer is more accurate if the method is called multiple times although if it is called enough in Java 8 the String objects could be unpacked on to the heap with Escape analysis and might not exist at all even the one which get returned in the method is inlined.Everara
S
13

s = s + "5";

Is translated to:

String s = new StringBuilder(s).append("5").toString();

For now, one Object is created.


s = s.substring(0,1); 

Creates a new String.


s = s.toLowerCase();

Creates a new Object.


return s.toString(); 

Doesn't create a String, it returns an already created one.

Slashing answered 27/7, 2013 at 13:26 Comment(2)
"s.toString(); " returns same string? are you sure?Hamblin
@loki yes.. toString() { return this} Kerrill
P
9

Some of the other answers do make sense, but what about the string literal?

String s = "HI";

For the string literals, when a .java file is compiled into a .class file, any string literals are noted in a special way, just as all constants are. When a class is loaded (note that loading happens prior to initialization), the JVM goes through the code for the class and looks for string literals.

When it finds one, it checks to see if an equivalent String is already referenced from the heap. If not, it creates a String instance on the heap and stores a reference to that object in the constant table

Once a reference is made to that string object, any references to that string literal throughout your program are simply replaced with the reference to the object referenced from the string literal pool.

Hence there should be four Java objects, although when the same method is called again and again then there would only be three objects as in the application the string literal pool contains the literal "HI".

Also, for more information on why new objects are created when the above method blocks are exectued we can also check the hash codes which are different for different strings (String being immutable.)

  public static void main(String[] args)
  {
      NumberOfString str = new NumberOfString();
      String s = str.makeStrings();
      System.out.println(s.hashCode());
  }

  public String makeStrings()
  {
      String s = "HI";
      System.out.println(s.hashCode());
      s = s + "5";
      System.out.println(s.hashCode());
      s = s.substring(0, 1);
      System.out.println(s.hashCode());
      s = s.toLowerCase();
      System.out.println(s.hashCode());
      return s.toString();
  }

You get the following output:

2305
71508
72
104
104

Should we not count in the String literal object in the above example?

Pamella answered 29/7, 2013 at 5:36 Comment(2)
Based on the answer given in the OP's question, we can assume that they are already in the String pool. Nonetheless, good answer (+1).Slope
The original question states "How many String objects will be created when this method is invoked?", inferring that the class has already been loaded and the method is being called from another piece of code. Based on your explanation, the String literal is created when the class is loaded, not specifically when this method is invoked, and therefore would not count toward the total in question.Selfdeception

© 2022 - 2024 — McMap. All rights reserved.