1

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 ?

Zabuzard
  • 25,064
  • 8
  • 58
  • 82
Sohail Ashraf
  • 10,078
  • 2
  • 26
  • 42
  • Actually this doesn't answer my question. I need to know whether the new keyword will create the entry in string pool or not. – Sohail Ashraf Mar 30 '21 at 07:23
  • yes it will. and yes, that is explained in the answers on that thread – Stultuske Mar 30 '21 at 07:26
  • 1
    No, your `new String(..)` will never place created sting in string pool by itself. You would need to invoke `intern()` explicitly and it will be placed in pool only if pool didn't have such string there. But since you used in constructor `"Cat"` string literal (and literals are placed/reused from pool) you can be sure that pool will contain string representing `Cat` sequence. – Pshemo Mar 30 '21 at 07:29
  • @Stultuske No it won't. The compiler and the `intern()` method put strings into the string pool. Not the `new` keyword. This code when executed creates exactly one `String`. – user207421 Mar 30 '21 at 07:30

4 Answers4

7

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.

Zabuzard
  • 25,064
  • 8
  • 58
  • 82
  • 1
    `"Cat"` does nothing. Specifically it does *not* 'look up the string pool. The compiler has already put it into the string pool because it is a string literal. When this code runs the `new` keyword creates one string. Period. – user207421 Mar 30 '21 at 07:31
  • @user207421 right. I added some details and rephrased it – Zabuzard Mar 30 '21 at 07:39
  • Sure but you keep talking about ' the `"Cat"` call'. This means nothing. And it isn't 'for most Java implementations'. Pooling of constant strings by the compiler is required by the JLS of *all* implementations. – user207421 Mar 30 '21 at 08:28
  • Well, somehow you have to phrase things in a way that beginners can understand them as well. I think "cat call" is accurate enough without being wrong or anything. The JLS mandates that string literals are interned but it does not explain at all how this should be implemented. Especially not whether this happens at compile-time or not (as also hinted by Stephen C in his comment section). Feel free to suggest an edit to the question of how you would phrase it instead, because I do not really get what exactly is _wrong_ or not accurate enough in your opinion, thanks. – Zabuzard Mar 30 '21 at 08:56
  • Come off it. There are only two words being discussed here: `"Cat"` and 'call'. The first is in the question, so it can only be 'call', i.e. the entire notion that the string literal does something, which I have already stated. I agree that the [JLS](https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.5) is not only vague but incorrect as to how constant string pooling is achieved, as the compiler doesn't call `String.intern()`, but you need to address your error that encountering a string literal at runtime does something. It doesn't. – user207421 Mar 30 '21 at 10:28
2

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.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • We can say with certainty that the compiler has already put it into the string pool. – user207421 Mar 30 '21 at 07:31
  • 1
    Actually, no we can't. Not if you put your language lawyer's hat (or is it a wig?) on and read the JLS carefully. >>In practice<< this will be true for all Hotspot JVMs ... – Stephen C Mar 30 '21 at 07:41
0

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.

krishna thota
  • 182
  • 1
  • 3
  • 8
-1

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.

Dharman
  • 30,962
  • 25
  • 85
  • 135