For the below statement in a program, how many objects will be created in heap memory and in the string constant pool?
I need clarity in object creation. Many sources I've read are not elaborating. I am confused when the object gets destroyed.
String a="MAM"+"BCD"+"EFG"+"GFE";
How many objects will be created?
I am looking for good material about the life cycle of objects, methods and classes and how the JVM handles them when they are dynamically changed and modified.
"MAM"+"BCD"+"EFG"+"GFE" is a compile-time constant expression and it compiles into "MAMBCDEFGGFE" string literal. JVM will create an instance of String from this literal when loading the class containing the above code and will put this String into the string pool. Thus String a = "MAM"+"BCD"+"EFG"+"GFE"; does not create any object, see JLS 15.18.1. String Concatenation Operator +
The String object is newly created (§12.5) unless the expression is a compile-time constant expression (§15.28).
It simply assigns a reference to String object in pool to local var a.
Only one object is created.
string s1 = "java";
string s2 = "ja" + "va";
s.o.p(s1==s2);
The statement yields true.
String s1="java";
string s2 = "ja";
String s3 = s2 +"va";
s.o.p(s1==s3);
The statement yields false.
So minimum one apparent should be permanent, then '+' operator generates new string object (in non constant pool using new()).
So, the question you asked does not have one also permanent. This means it creates only one object.
Exactly one object is created and placed in the constant pool, unless it already exists, in which case the existing object is used. The compiler concatenates string constants together, as specified in JLS 3.10.5 and 15.28.
A long string literal can always be broken up into shorter pieces and written as a (possibly parenthesized) expression using the string concatenation operator +
http://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.5
Most answers seem to focus that a) the complete expression is one compile time constant and b) that the line itself does not construct a new object but only a reference to one object.
However noone so far has mentioned, that String itself contains a reference to an internal char[] (which is also in the constant pool).
Summary: There are two objects in the constant pool (String and char[]). The line does neither create nor destroy any object.
And regarding:
I am confused when the object gets destroyed.
No object is destroyed, since stuff in the constant pool will only be destroyed if the class itself would be unloaded. At most you can say, that the reference a will go out of scope eventually.
Only one object will be created since String a will compile into "MAMBCDEFGGFE".
Answers stating a single heap object in your example are correct. However, consider this code:
public class Tester
{
public String a="MAM";
public String b ="BCD";
public String c = "EFG";
public String d ="GFE";
public Tester()
{
String abcd = a + b + c + d;
}
}
In this example, there are 7 strings being created. a,b,c and d are not compiled into a single constant - they are members. 1 string is then created for each + operator - semantically speaking, + is a concatenation but logically it is creating a new string in memory. The first 2 operator strings are discarded immediately and are now eligible for garbage collection but the memory churn still occurs.
Technically there in an 8th object. The instance of Tester.
Edit: This has been proved to be nonsense in the comments
Related
String newString=new String("JAVA");
newString="JAVA8";
WHAT will happen here if we print newString we know output will be JAVA8 only but 2nd line created new object in heap or constant pool.
How its behave internally
In Java Strings are immutable.
What that means is that once a String object is created it cannot be updated.
Also Java has something called Java String Pool, a memory location where Java stores Strings.
To minimize the memory space used by this String Pool, Java performs Interning when a new String literal is create using the following statement.
String s = "apple";
What Interning means is that JVM looks in the String Pool to see if the string literal "apple" exists, if it does it just passes its reference to new variable, no new object is created, if it does not exist it creates a new object passes its reference and also can pass the same reference if another string is created with same value. For Example:
String t= "apple";
If you check if the both strings created above are reference to the same string literal in string pool, you can do that as follows:
System.out.println(s == t); // True
When a string is created using new keyword it always creates a new Object in the String pool, even if the string literal exists in the string pool.
String u = new String("apple");
You can check that the new object is created by following statement:
System.out.println(s == u); // False
System.out.println(t == u); // False
In yoru case the first statement created a new object in String pool and passed its reference. The second line created another object and passed its reference. The first object is still in String pool but not being referenced by any variable and eventually the memory occupied by it will be released by Garbage collection.
Hope this answers your question, you can read about Java String pool to know more.
First, newString is not a String!!!
newString is a reference to an instance of the class String! A C programmer would name it pointer and write String* newString.
With
String newString = new String( "JAVA" );
you declare the variable newString of type "reference to String" and assign the reference to (the address for) the new object, created by a call to the constructor of the class java.lang.String from the compile time constant "JAVA".
newString = "JAVA8";
now assigns the reference to the compile time constant "JAVA8" to that previously created variable. At the same time, the previously reference object gets abandoned (no more references to that object were hold) and therefore it is now ready to be garbage collected.
Most Java implementations do store the compile time constants not on the heap, and strings are usually stored in the string pool. Also it is possible that the call to new String() will never be executed; instead the compiler will directly use the reference to the compile time constant. Or it will be executed and the resulting String object is stored on the Heap, with or without referencing the string value in the string pool.
The details can be found in the Java Language Specification and the JVM Specification for the respective version, and if that says "implementation dependent", in the documentation for the respective JVM/Java implementation.
I am studding and preparing for OCP 1Z0-815 and I read from this excellent preparing book:
Deshmukh, Hanumant. OCP Oracle Certified Professional Java SE 11 Programmer I Exam Fundamentals 1Z0-815: Study guide for passing the OCP Java 11 Developer Certification Part 1 Exam 1Z0-815 (p. 99). Enthuware. Edição do Kindle.
String str = "hello";
for( int i = 0; i < 5; i + +) {
str = str + i;
}
The above creates one String object containing "hello" at the beginning and then two more in each iteration of the loop - a String containing the int value of i and the concatenated String. Thus, overall, the above code creates 1 + 2* 5 = 11 Strings. However, if you are asked how many String will be eligible to be garbage collected, the answer is not that easy. The Java Language Specification mentions in Section 15.8.1 that the non-string operand of the + operator is converted to a String at runtime but it does not clearly tell whether this String goes to the String pool (in which case it will not be garbage collected) or not.
Let me show you another piece of code:
String s = "hello";
int k = 100;
s = s + " 123" + k;
In this case, JLS section 15.8.1 clearly says that a compiler may avoid creating multiple strings altogether by making use of a StringBuilder. Thus, it is not possible to tell how many Strings will be created and how many will be eligible to be garbage collected...
The statement above "...The Java Language Specification mentions in Section 15.8.1 that the non-string operand of the + operator is converted to a String at runtime but it does not clearly tell whether this String goes to the String pool..." drove me to search around but I didn't manage to find an explanation: as far as I don't see "new" I understand that indeed it goes to String pool and so it is not an object. Consequentlly it is not elegiable for garbage collection at all. Am I saying something wrong?
In other words, as far as understand, every loop will result in a constant string in String Pool in Heap (Java 11 in mind instead of Java 7). hello0, hello1, hello2 and so on and there will not be any candidate for Garbage Collection at all. I understand that Garbage Colletion "clean" objects created by new operator and doesn't act on String Pool.
Based on conclusion paragraph, "... section 15.8.1 clearly says that a compiler may avoid creating multiple strings altogether by making use of a StringBuilder. Thus, it is not possible to tell how many Strings will be created and how many will be eligible to be garbage collected..." I assume it is saying that I can't discover how many Strings are created in String Pool in second code example (wihtout loop) because StringBuilder is used behind the scene and we know that StringBuilder manipulate concatenation in memory avoiding creating many String literals. Well, if that is the case, I still can assume in first code thatt fofr each loop will result in a Literal String (hello0, hello1...) that goes to String Pool and will not be eligible for Garbage Collection in pratical terms. Am I wrong?
PS.: You may comment that Garbage Collection acts on String Pool but I understand that in pratical terms, literal string in String Pool resides for a so long time that we can consider it is never eligible for Garbage Collection before program ends (" there is an implicit reference to the String object in the code of every method that uses the literal." and " all string literals in the string pool are reachable until the program is terminated and thus not eligible for garbage collection"
as far as I don't see new I understand that indeed it goes to String pool and so it is not an object.
First of all, the Java Language Specification doesn't mention the string pool specifically. What it actually says is that if two string-valued constant expressions are equal, then they will be the same object. (This covers string literals, but also covers cases like String s = "a" + "b";)
The string pool is >>a<< mechanism for doing that, but the JLS doesn't mandate a specific mechanism.
What about new?
The JLS also says that the new operator always produces a brand new object:
"The value of a class instance creation expression is a reference to the newly created object of the specified class. Every time the expression is evaluated, a fresh object is created." (JLS 15.9.4)
The consequence of this is:
String a1 = new String("a");
System.out.println("a" == a1); // prints "false"
This must be do, because the new String is not a fresh one. Since the string pool is a de-duping mechanism, we can conclude that new String("a") is NOT putting the new String object into the string pool.
Likewise, the + operator creates a new String:
"The result of string concatenation is a reference to a String object that is the concatenation of the two operand strings. The characters of the left-hand operand precede the characters of the right-hand operand in the newly created string." (JLS 15.18.1)
The JLS also says that the compiler can optimize expressions involving +:
"An implementation may choose to perform conversion and concatenation in one step to avoid creating and then discarding an intermediate String object. To increase the performance of repeated string concatenation, a Java compiler may use the StringBuffer class or a similar technique to reduce the number of intermediate String objects that are created by evaluation of an expression.
For primitive types, an implementation may also optimize away the creation of a wrapper object by converting directly from a primitive type to a string." (JLS 15.18.1)
But note that this optimization is only permitted within an expression, not across multiple statements.
The JLS says nothing about other String operations. For their specification we need to refer to the javadocs. In current versions, the only String methods that state that a new string is always created are the two join methods.
But likewise, the only String method that specifically mentions the string pool is the intern method.
That is what the specifications say. What do String implementations actually do?
Well if you examine the standard source code for Java SE implementations going back to Java 1.1, you will find that apart from intern, no String methods put objects into the string pool. None.
You also said this:
I understand that in practical terms, literal string in String Pool resides for a so long time that we can consider it is never eligible for Garbage Collection before program ends.
That is true is most cases. The exception is code that is you can create a classloader and use that to load classes dynamically. If that classloader becomes unreachable, and there are no other references to the classes it loaded, then its string literals may be unreachable ... before the program ends.
This is liable to happen if you use a product (e.g. a web container) where new versions of classes can be hot-loaded.
Finally if we look at the example:
String str = "hello";
for (int i = 0; i < 5; i++) {
str = str + i;
}
In practice:
The first time we run this, a new String object will (probably) be created for the "hello" literal.
On each loop iteration, at least one new String will be created. It is possible that an intermediate String will be created to represent the string value of i, but the compiler is permitted to optimize that away.
None of the intermediate String objects will be interned / added to the string pool.
All but the "hello" literal and the final value will be unreachable.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
When should we use intern method of String?
what is string interning?
Please explain the inner workings of the following code:
System.out.println(new String("ABC").intern()==new String("ABC").intern());
In the above code it prints "true". But according java rules, in the case of the new operator, it always creates a new object. object.intern() method also creates an object in the string pool. So my question is, in the above code how many objects are created.
According to me, 3 new objects will created. One goes to String pool, and two anonymous objects will be created by the new operator. But i am not sure.
If i am wrong please explain.
Assuming no cleverness in the optimizer, two objects are created. (A smart enough optimizer could optimize this to just an unconditional true, in which case no objects are created.)
tl;dr version: You were almost right with your answer of 3, except that the string that goes into the String pool is not generated as part of this statement; it's already created.
First, let's get the "ABC" literal out of the way. It's represented in the runtime as a String object, but that lives in pergen and was created once in the whole life of the JVM. If this is the first class that uses that string literal, it was created at class load time (see JLS 12.5, which states that the String was created when the class was loaded, unless it previously existed).
So, the first new String("ABC") creates one String, which simply copies the reference (but does not create a new object) to the chars array and hash from the String that represents the "ABC" literal (which, again, is not created as part of this line). The .intern() method then looks to see whether an equal String is already in permgen. It is (it's just the String that represents the literal to begin with), so that's what that function returns. So, new String("ABC").intern() == "ABC". See JLS 3.10.5, and in particular:
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.28) - are "interned" so as to share unique instances, using the method String.intern.
The same thing exactly happens with the second occurrence of new String("ABC").intern(). And, since both intern() method return the same object as the "ABC" literal, they represent the same value.
Breaking it down a bit:
String a = new String("ABC"); // a != "ABC"
String aInterned = a.intern(); // aInterned == "ABC"
String b = new String("ABC"); // b != "ABC"
String bInterned = b.intern(); // bInterned == "ABC"
System.out.println(new String("ABC").intern()==new String("ABC").intern());
// ... is equivalent to...
System.out.println(aInterned == bInterned); // ...which is equivalent to...
System.out.println("ABC" == "ABC"); // ...which is always true.
When you call intern() method, jvm will check if the given string is there, in string pool or not. If it is there, it will return a reference to that, otherwise it will create a new string in pool and return reference to that.
In your case : System.out.println(new String("ABC").intern()==new String("ABC").intern());
The first new String("ABC").intern() will create a string "ABC" in pool.When you call new String("ABC").intern() second time, jvm will return the reference to previously created string.That is the reason you are getting true when comparing both(btn are pointing to same reference).
I believe you are right, as new operation create a new object so there are 2 anonymous objects and intern() creates a new string in the string pool only if it is not already and returns it's reference
I am new in java.
In java, String is a class.But
we do not have to use new keyword to create an object of class String where as new is used for creating objects for other classes.
I have heard about Wrapper classes like Integer,Double which are similar to this.
But String is not Wrapper,isn't it?
Actually what is happening when i use
String message = "Hai";
??
How it is different from
String message = new String("Hai");
Here is message a reference variable or something else??
Are there other classes which do not require new to create object ??
With the following line you are not creating a new String object in the heap but reusing a string literal (if already available):
String message = "Hai";
"Hai" is a string literal in the string literal pool. Since, strings are immutable, they are reusable so they are pooled in the string literal pool by the JVM. And this is the recommended way, because you are reusing it.
But, with the following you are actually creating a new object (in the heap):
String message = new String("Hai");
new String("Hai") is a new String object. In this case, even if the literal "Hai" was already in the string literal pool, a new object is created. This is not recommended because chances are that you might end with more than one String objects with the same value.
Also see this post: Questions about Java's String pool
Are there other classes which do not require new to create object ??
Actually, you can not create any object in Java without using the keyword new.
e.g.
Integer i = 1;
Does, not mean that the Integer object is created without using new. It's just not required for us to use the new keyword explicitly. But under the hood, if the Integer object with value 1 does not already exist in cache (Integer objects are cached by JVM), new keyword will be used to create it.
The Java language specification allows for representation of a string as a literal. You can consider it a shortcut initialization for a String that has one important side-effect that is different from regular initialization via new
String literals are all interned, which means that they are constant values stored by the Java runtime and can be shared across multiple classes. For example:
class MainClass (
public String test = "hello";
}
class OtherClass {
public String another = "hello";
public OtherClass() {
MainClass main = new MainClass();
System.out.println(main.test == another);
}
}
Would print out "true" since, both String instances actually point to the same object. This would not be the case if you initialize the strings via the new keyword.
String and Integer creation are different.
String s = "Test";
Here the '=' operator is overloaded for string. So is the '+' operator in "some"+"things".
Where as,
Integer i = 2;
Until Java 5.0 this is compile time error; you cant assign primitive to its wrapper. But from Java 5.0 this is called auto-boxing where primitives are auto promoted to their wrappers wherever required.
String h1 = "hi";
will be different from
String h2 = new String("hi");
The reason is that the JVM maintains a string table for all string literals. so there will be an entry in the table for "hi" , say its address is 1000.
But when you explicitly create a string object, new object will be created, say its address is 2000. Now the new object will point to the entry in the string table which is 1000.
Hence when you say
h1 == h2
it compares
1000 == 2000
So it is false
In java
"==" compares the left & right hand sides memory locations(and not the value at that memory location) and therefore in case of
new String("hai")==new String("hai")
it returns false.
In case of "Hai"=="Hai", java doesn't allocate separate memory for same string literal therefore here "==" returns true. You can always use equals method to compare values.
The reason why doesn't recommended because of memory, using new keyword and creating String object, JVM create 2 object between HEAP and SCP, but using just literal is that JVM creating only SCP. That's why we creating String object, just using literal.
check the following program:
Run it in sun java hostspot jvm, everything will be "true".
--------updated: got the answer by Stephen and Danie,changed the program to add string intern method-----------
how it will become, if B is separate compiled not together with A, what will happen???, for example , B is compiled and put in a jar, and put its class path when run TestStringEqual ??
Also, is this java compile time optimization, or java run time optimization, or java language specification defined ??
Also, it this program comes the same result on different VMs, or just one VM feature?
thanks
public class TestStringEqual {
public static String HELLO = "hello";
private String m_hello;
public TestStringEqual() {
m_hello = "hello";
}
public static void main(String[] args) {
String a = "hello";
String b = "hello";
System.out.println("string a== string b:" + (a == b));
System.out.println("static memebr ==a:" + (HELLO == a));
System.out.println("instance field ==a:"
+ (new TestStringEqual().getHello() == a));
System.out.println("hello in B ==a:" + (B.B_HELLO == a));
System.out.println("interned new string object in heep==a:"
+ ( new String("hello").intern() == a));
}
public String getHello() {
return this.m_hello;
}
}
class B{
public static final String B_HELLO = "he"+"llo";
}
There is really no mystery about this at all. You just need to know three basic facts about Java:
The '==' operator for object references tests if two object references are the same; i.e if they point to the same object. Reference JLS 15.21.3
All String literals with the same sequence of characters in a Java program will be represented by the same String object. Reference JLS 3.10.5 So (for example) "hello" == "hello" is comparing the same object.
Constant expressions are evaluated at compile time. Reference JLS 15.28. So (for example) "hell" + "o" is evaluated at compile time, and is therefore equivalent to the literal "hello".
These three facts are stated in the Java Language Specifications. They are sufficient to explain the "puzzling" aspects behaviour of your program, without relying on anything else.
The more detailed explanation involving the string pool, string literals being interned by the class loader, the bytecodes emitted by the compiler, etc, etc ... are just implementation details. You don't need to understand these details if you understand what the JLS is saying, and they don't really help to make the JLS clearer (IMO).
Notes:
The definition of what is and what isn't a constant expression is a little involved. Some things that you might imagine to be constant valued, are in fact not. For instance, "hello".length() is not a constant expression. However, a concatenation of two string literals is a constant expression.
The explanation of equality of string literals in the JLS does in fact mention interning as the mechanism by which this property of literals is implemented.
On the JVM level, the LDC (load constant) instruction is used to push a string literal onto the stack. For performance reasons, the string literal isn't stored in the code itself; it's stored in the constant pool of the class. The constant pool is a table which appears at the beginning of a class file containing string literals, numeric literals, field and method descriptors, and a few other things. LDC is followed by a byte specifying the string's index in the constant pool. (If one byte is not large enough, the compiler will use LDC_W, which is followed by a 16-bit offset. Hence the limit of 65,536 constants.)
If the same string literal occurs twice in the same class, javac is smart enough to create only one entry in the constant pool. When a class is loaded, the JVM creates actual String objects from the data in the constant pool. LDCs which contain the same offset into the constant pool will thus cause the same String to be pushed onto the stack. Instructions like IF_ACMPEQ (which checks for reference equality as == does) will then recognize the strings as identical.
See the JVMS for more info.
It's an immutable string (unable to be mutated or changed), not an immune one, though I suppose you could argue that it's immune from change :-)
That means you cannot change the underlying string itself, you can only assign a different string to the variable. So:
string a = "Hello";
a = "Goodbye";
doesn't change the memory where "Hello" is stored, it changes a to point to a different memory location where "Goodbye" is stored.
This allows Java to share strings for efficiency. You can even get cases where strings like "deoxyribonucleic acid" and "acid" may share space, where the latter points to a specific location within the former. Again, this is made possible by the immutable nature of such strings.
In any case, == will check to see if the strings refer to the same underlying object, not something that's often useful. If you want to see if the strings are equal, you should be using String.equals() or one of its variations.
It is fairly simple: the compiler will generate a (bytecode) constant for the string "hello" the first time it encounters it. In normal assembler it would be in the .TEXT section.
The subsequent "hello" strings will then point to that same constant, since there is no need to allocate new space or create a new constant. The reason this is so is because strings are immutable and if one is assigned a new value new memory is needed for it anyway.
It will probably not work on input, i.e. if you let a user input "hello" and ==-compare that to the compile-time hello strings you'll likely get false.
As far as a==b goes, it seems the compiler is making the shortcuts and sharing the same string object. When I declare my varuiables as follows, I get a==b is false.
String a = "hello";
String b = "hell";
String temp = "o";
if (new java.util.Random().nextDouble() < 0.5) b += temp;
else b += "o";
If I do String b = "hell"+"o"; I still get a==b as true.