Memory allocation when creating new String as literal/new Object

Priyak Dey :

NOTE: Before marking it duplicate, please read the question. This is not a question about where is the constant pool stored, how intern works, how many objects are created or how using a different creation technique/using intern affects the == results.. !!

String s1 = "Hello";
String s2 = new String("Hello");

Field declaredField = String.class.getDeclaredField("value");
declaredField.setAccessible(true);

byte[] arr1 = (byte[])declaredField.get(s1);
byte[] arr2 = (byte[])declaredField.get(s2);

Now, s1 == s2 = False, arr1== arr2 = True.

My question is how are the objects being stored in the memory.

First line does create a new String type object on the pool. Second line does create it on the heap as a regular object

But the underlying byte[] arr is the same. This makes me think, somehow JVM does this check if such an existing byte[] already exists and points all references to the same arr. Does this mean the underlying array is cached in the pool, no matter we use the literal or new keyword?

So s = "something" creates a new String type object on the pool along with a underlying array holding the data - which is also created on the pool.

s = new String("something") -> creates the String type object on the heap, but the underlying array still stored in the pool/if already exists, a reference is just created.

Is my understanding even correct ?

Anybody having any pointer to nice article will also be nice, since this is bugging me for a long time :(

Maxim Popov :

What java version do you use? I check it on 11 jdk and type of String.value is char[]. All next words based on 11 JDK version.

The reason for this behavior is a String constructor.

public String(String original) {
    this.value = original.value;
    this.hash = original.hash;
}

As you can see, the value field is copied from original String object. Since you are using "Hello" for new String(...) argument, "Hello" is gotten from the String pool and passed to the constructor, where the value field is copping to a new String object.

You can change your code a bit for reaching expected behaviour:

String s1 = "Hello";
String s2 = new String("Hell") + "o";
Field declaredField = String.class.getDeclaredField("value");
declaredField.setAccessible(true);
char[] arr1 = (char[])declaredField.get(s1);
char[] arr2 = (char[])declaredField.get(s2);
assert arr1 != arr2;
assert s1.equals(s2);

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=292102&siteId=1