How many Strings are getting created with the new operator

1.1k views Asked by At

How many Strings are getting created with new operator.

let say I am creating a string with new operator.

String str = new String("Cat")

Will it create 2 strings one in heap and other one is in string pool?

if it creates string in string poll as well then what is the purpose of string intern method ?

4

There are 4 answers

5
Zabuzard On BEST ANSWER

How many objects?

Will it create 2 strings one in heap and other one is in string pool?

When you write "Cat", you end up populating the pool with Cat and the "Cat" call loads this object from the pool. This typically happens already at compile time. Then new String(...) will create a new string object, ignoring the pool completely.

So this snippet leads to the creation of two objects. To clear up your confusion, consider the following example:

String first = "Cat";
String second = "Cat";
String third = "Cat";
String fourth = new String("Cat");

Here, two objects are created as well. All the "Cat" calls will load the string out of the pool, so first == second == third and fourth will be its own object since it used new, which always leads to a creation of a new object, bypassing any sort of caching mechanisms.

Whether the objects are created on the heap or stack is not really defined. Memory management is totally up to the JVM.


String pool details

For most of Java implementations, the string pool is created and populated already during compilation. When you write "Cat", the compiler will put a string object representing Cat into this pool and the "Cat" in your code will be replaced by loading this object from the pool. You can see this easily when you disassemble a compiled program. For example, source code:

public class Test {
    public static void main(String[] args) {
        String foo = "Hello World";
    }
}

disassembly (javap -v):

Classfile /C:/Users/Zabuza/Desktop/Test.class
  Last modified 30.03.2021; size 277 bytes
  SHA-256 checksum 83de8a7326af14fc95fb499af090f9b3377c56f79f2e78b34e447d66b645a285
  Compiled from "Test.java"
public class Test
  minor version: 0
  major version: 59
  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
  this_class: #9                          // Test
  super_class: #2                         // java/lang/Object
  interfaces: 0, fields: 0, methods: 2, attributes: 1
Constant pool:
   #1 = Methodref          #2.#3          // java/lang/Object."<init>":()V
   #2 = Class              #4             // java/lang/Object
   #3 = NameAndType        #5:#6          // "<init>":()V
   #4 = Utf8               java/lang/Object
   #5 = Utf8               <init>
   #6 = Utf8               ()V
   #7 = String             #8             // Hello World
   #8 = Utf8               Hello World
   #9 = Class              #10            // Test
  #10 = Utf8               Test
  #11 = Utf8               Code
  #12 = Utf8               LineNumberTable
  #13 = Utf8               main
  #14 = Utf8               ([Ljava/lang/String;)V
  #15 = Utf8               SourceFile
  #16 = Utf8               Test.java
{
  public Test();
    descriptor: ()V
    flags: (0x0001) 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 static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
    Code:
      stack=1, locals=2, args_size=1
         0: ldc           #7                  // String Hello World
         2: astore_1
         3: return
      LineNumberTable:
        line 3: 0
        line 4: 3
}
SourceFile: "Test.java"

As you see, there is

#7 = String             #8             // Hello World
#8 = Utf8               Hello World

and the section in the method is replaced by

0: ldc           #7

which loads Hello World from the string pool.


String interning

what is the purpose of string intern method?

Well, it gives you the possibility to swap out your string against the version from the pool. And to populate the pool with your string in case it did not exist there before. For example:

String first = "hello"; // from pool
String second = new String("hello"); // new object
String third = second.intern(); // from pool, same as first

System.out.println(first == second); // false
System.out.println(first == third); // true

Use case

I have not seen a real world application for this feature yet though.

However, I could think of an use-case where you create, possibly long strings dynamically in your application and you know that they will re-occur later again. Then you can put your strings into the pool in order to trim down the memory footprint when they occur again later on.

So lets say you receive some long strings from HTTP responses and you know that the responses, most of the time, are the exact same and you also want to collect them in a List:

private List<String> responses = new ArrayList<>();

...

public void receiveResponse(String response) {
    ...
    responses.add(response);
}

Without interning, you would end up keeping each string instance, including duplicates, alive in your memory. If you intern them however, you would not have duplicate string objects in memory:

public void receiveResponse(String response) {
    ...
    String responseFromPool = response.intern();
    responses.add(responseFromPool);
}

Of course, this is a bit contrived as you could also just use a Set instead here.

0
Pratik Bhusari On

We can use intern() method to put it into the pool or refer to another String object from the string pool having the same value.

As the above line, either 1 or 2 string will be created.

If there is already a string literal “Cat” in the pool, then only one string “str” will be created in the pool. If there is no string literal “Cat” in the pool, then it will be first created in the pool and then in the heap space, so a total of 2 string objects will be created.

2
Stephen C On

The new operator is creating exactly one String instance.

A second String instance is at some point in time created to represent String literal argument passed to the String(String) constructor. But we cannot say with certainty that it is created when we execute that statement. (It may have been created already.)

We can say with certainty the following:

  1. The Object that represents the literal is created before the new operator is invoked.
  2. It is created once during the lifetime of the application1.

Interestingly, we cannot say with absolute certainty that a "string pool" is involved, or that String.intern is used at any point. The Java 15 JLS states this in section 3.10.5:

"Moreover, a string literal always refers to the same instance of class String. This is because string literals - or, more generally, strings that are the values of constant expressions (§15.29) - are "interned" so as to share unique instances, as if by execution of the method String.intern (§12.5)."

The "as if by" phraseology is stating that the runtime system must appear to behave in a particular way ... but it need not actually be implemented that way. If there was a viable alternative to calling String.intern on string literals that gave String objects had the right uniqueness properties, that would be an acceptable implementation too. According to the JLS!

(In practice all Hotspot JVMs do use a string pool and do use String.intern. But that is an "implementation detail".)


1 - Unless the class that contains that statement is loaded multiple times.

0
krishna thota On

when we create a String object String s1=new String("hello");, the string literal "hello" stores in String constant pool and the reference stored in Heap memory and s1points to that reference. String s2="hello"; in this case, the string literal stores in String constant pool and s2 being referenced to that address directly.String s3=s1.intern(); if you try this, you are making the s3 points to same address of string literal stored in string constant pool.

String s1=new String("hello");  
String s2="hello";  
String s3=s1.intern();//returns string from pool, now it will be same as s2  
System.out.println(s1==s2);//false because reference variables are pointing to different instance  
System.out.println(s2==s3);//true because reference variables are pointing to same instance  

I hope its helpful, please post if you have further questions.