Immutable strings in java? - java

String s = "java";
s.substring(1); // ava
Considering the immutability of strings, compiler doesnot modify 's' but creates a new object or you can say that there is space for 'java' as well as 'ava' in memory..
What happens to this 'ava', as nothing is pointing to it or it's not being referenced by anything..
One more question... If i would have written String s = new String("java"); // 'java' is not in string literal pool....
The 'ava' would be in the string literal pool then or not ?

What happens to this 'ava', as nothing is pointing to it or it's not being referenced by anything..
The newly constructed String object immediately becomes eligible for garbage collection.
As to your second question, I don't think there's any difference between the following two expressions as far as the string literal pool is concerned:
String s = "java";
String s = new String("java");
In both cases, the literal "java" would be in the pool. (But in the second case, s would not refer to the "java" string that's in the pool, but to a different String that also has the characters "java".)

1) What happens to this 'ava', as nothing is pointing to it or it's not being referenced by anything..
As you have not assigned 'ava' to any object means 'ava' is not being pointed by any object so it would be eligible for garbage collection.
2) The 'ava' would be in the string literal pool then or not ?
No it would be in string literal pool.

s.substring(1) creates a new String pointing to the underlying char array of s. The important thing to realise here is that the char array is shared between these two objects. If you use the String(String) constructor a new char array is created containing the referenced characters.
If you throw away the reference to s, if you have a reference to the result of the substring() operation then you have a reference to the full underlying char array.
In your example you're not storing a reference to the newly created String. So that will be garbage-collected very quickly. The underlying array is still referenced by s, however.

Related

Does the garbage collector count this as a collectable object?

Given a string
String x = "hello";
As far as I remember, x now is a constant with a reference but when in the middle of the code I change value to
x = "hey";
hello stays stuck in the memory and the GC frees it. Is it true ? If not, could you explain more how the GC work?
As far as I remember, x now is a constant
No. The reference is not a constant. It is a reference to an immutable, but the reference itself (the "pointer") is not (crediting Turing85 for the clarification). For x to be considered a constant, it needs to be declared with the keyword final (then the reference itself will be a constant). For example, final String x = "hello";. Because it is not a constant, it allows you to change the reference later on in the code x = "hey";. THAT SAID, because of how Java manages strings (and other immutables), "hello" and "hey" are indeed constants. They are "permanent" members of the String pool. Meaning that, their life cycle is the same as the life of your program. I think there are ways change this, but by default I am pretty sure this is the case. So, if you create multiple objects with the same String value:
String a = "hello"; // will add "hello" to String pool if it doesn't exist there
String b = "hello"; // finds "hello" in the string pool and returns back the same reference to this variable
String c = "hello"; // same as `b` above
However, if you create a new String using the copy constructor:
String d = new String("hello"); // Will add new "hello" to heap even though it already exist in string pool. (Thanks Holger!)
Explaining in detail how the GC works is not very easy to explain; especially in a single SO post. I don't even fully understand it myself. But, since the purpose of the pool is to eliminate the need to create "infinite" copies of the same thing over and over, "hello" and "hey" won't be garbage-collected. As for the variable x, it will be handled by the GC depending on many factors, one of which is scope. Also, there is no guarantee as to when (if ever) the GC will cleanup an unused resource.
I think this is accurate, albeit somewhat ambiguous or incomplete. But at a high-level, this is how GC will work in this case to the best of my knowledge.
UPDATE: Thanks to #Holger for bringing this to my attention. When a String Literal is assigned to a variable, it will first look for such value in the String Pool to see if such string exists. If it doesn't, it creates it and assigns it to the variable. HOWEVER, when a string is created with the new operator, it will add the new string JUST into Heap Memory. That's the main difference between assigning string literals vs. new strings to a variable.

How String pool manages references if we change string value?

If we have a String s = "Hello" It will create string "Hello" in string pool and some reference is pointing to string s what if I change s="World" .In string pool it will create new String "World" and now my reference is pointing to World. What will happen to "Hello" String?
From the documentation of String:
... String objects are immutable ...
String-constants known at compile-time are also treated specially. They are stored in a constant pool. All "equal" compile-time String-constant reference the same String-object. This is the reason why
String s1 = "Hello";
String s2 = "Hello";
System.out.println(s1 == s2);
will print true. There are some other interesting examples. I wrote an Ideone example a while back that demonstrates some of those interesting cases.
When one re-assings a value to some non-primitive type variable s, the old object still exists on the heap (as long as the Garbage Collector does not deem it eligible for collection). What is changed is where the variable s is referencing. In the case presented, a second String-constant is created at compile-time and s then references the second constant.
String objects are immutable, so what happens with your second assignment is only an object reference update.
String literal objects (like "Hello" and "World") will be referenced from Java's String pool (they are interned). As this counts as a reference, the "Hello" object will not be garbage collected after your reassignment. That will only happen if the code itself becomes unreachable (e.g. if the entire class was loaded dynamically and its class loader becomes now unreachable).

Need to know about String, String Constant pool and String intern method [duplicate]

This question already has answers here:
Questions about Java's String pool [duplicate]
(7 answers)
Closed 4 years ago.
Say if there are no strings in the String constant pool, and if I say,
String s = "Java";
Then how many objects will be created?
Now again nothing in the pool, and I say,
String s = new String("Java");
Now, how many objects will be created?
Now again nothing in the pool, and I say,
String s = new String("Java");
s.intern();
What will the intern method do?
Now again nothing in the pool, and I say,
String s = new String("Java");
String s1 = s.intern();
What will happen now?
Please answer as I am really confused about it.
As I read in SCJP5 Kathy Sierra book, that when you create a String with new, then 2 objects are created, one on the heap and one in the pool.
I will assume that in each example below you load and execute the code exactly once, in a new JVM each time. (I will also assume that nowhere else in your code do you use the literal "Java" ... since that would complicate things.)
1) Say if there are no strings in the String constant pool, and if i
say,
String s = "Java";
Then how many objects will be created ?
One string is created and added to the pool when method is loaded.
2) Now again nothing in the pool, and i say,
String s = new String("Java");
Now how many objects will be created.
One string is created and added to the pool when method is loaded.
A second string is created by the new when the code is run, and it is NOT added to the pool.
3) Now again nothing in the pool, and i say,
String s = new String("Java");
s.intern();
What will the intern method do ?
One string is created and added to the pool when method is loaded.
A second string is created by the new, and it is NOT added to the pool.
The intern call returns the first string. (You don't keep the reference ...)
4) Now again nothing in the pool, and i say,
String s = new String("Java");
String s1 = s.intern();
What will happen now?
Same as example 3. Thus, s1 will hold a reference to the String object that represents the "Java" string literal.
I read in SCJP5 Kathy Sierra book, that when you create a String with new, then 2 objects are created, one on the heap and one in the pool.
I doubt that the book said that exactly. (You are paraphrasing, and I think you have paraphrased somewhat inaccurately.)
However, your paraphrasing is roughly correct, though (an this is important!) the string object representing the literal is created and added to the pool when the code fragment is loaded1, not when it is executed.
And to address another point of confusion:
"What i actually meant was that from the answer that you gave, it seems that a String will always be added in the String constant pool."
That is incorrect. It is a false generalization.
While it is true for all 4 of the cases above, it will not be true for others. It depends on where the original string came from. In typical applications, most text data is read from a file, socket, or a user interface. When that happens, the strings are created from arrays of characters, either directly or via a library call.
Here is a simple (but unrealistic) example that shows creating a String from its component characters.
String s = new String(new char[]{'J', 'a', 'v', 'a'});
In the snippet above, only one String is created, and it is NOT in the String pool. If you wanted the resulting string to be in the string pool you need to explicitly call intern something like this:
String s = new String(new char[]{'J', 'a', 'v', 'a'});
s = s.intern();
... which will (if necessary) create a second string in the string pool2.
1 - Apparently, in some JVMs creation and interning string literals is done lazily, so it is not possible to say with 100% certainty when it actually happens. However, it will only occur once (per class that references the literal), no matter how many times the code fragment is executed by the JVM.
2 - There is no way to new a string into the string pool. It would actually be a violation of the JLS. The new operation is specified by the JLS as always creating a new object.
Then how many objects will be created?
There is one String in the pool.
Now how many objects will be created?
One String will be created, there is still one String in the pool.
What will the intern method do?
It will try to put a "Java" into the pool, find another "Java" there, are return a reference to that "Java" from step 1.
What will happen now?
The "Java" from step 1 will come back and s1 now refers to it.
Say if there are no strings in the String constant pool, and if i say,
String s = "Java";
Then how many objects will be created ?
One String object is created in intern pool.
s is assigned by that reference.
Now again nothing in the pool, and i say,
String s = new String("Java");
Now how many objects will be created.
Two String object is created.
One is interned "Java", and one is new String with the same content of "Java"
Now again nothing in the pool, and i say,
String s = new String("Java");
s.intern();
What will the intern method do ?
The intern() method will:
When the intern method is invoked, if the pool already contains a string equal to this String object as determined by the equals(Object) method, then the string from the pool is returned. Otherwise, this String object is added to the pool and a reference to this String object is returned.
So in this case, this String is added to the pool and a reference to this is returned
And the last question:
Now again nothing in the pool, and i say,
String s = new String("Java");
String s1 = s.intern();
What will happen now?
What happen here is:
String "Java" is added to the pool
New String is created, backed by the same char[] array "Java"
s.intern() look for a reference in the pool and s1 is assigned by the interned reference
String strObject = new String("Java");
and
String strLiteral = "Java";
Both expression gives you String object, but there is subtle difference between them.
When you create String object using new() operator, it always create a new object in heap memory.
On the other hand, if you create object using String literal syntax e.g. "Java", it may return an existing object from String pool (a cache of String object in Perm gen space, which is now moved to heap space in recent Java release), if it's already exists. Otherwise it will create a new string object and put in string pool for future re-use.
String s = "Java";
One object will be created in Pool.
Now again nothing in the pool, and i say,
String s = new String("Java");
One Object will be created in Heap
Now again nothing in the pool, and i say,
String s = new String("Java");
s.intern();
What will the intern method do ?
intern() method will copy the Sting object into pool, but it will be no use, as it is not referenced, hence there will be only object in Heap
Now again nothing in the pool, and i say,
String s = new String("Java");
String s1 = s.intern();
What will happen now?
one object in Heap and one object in Pool will be created.

Initializing a class object using literals

If I write this code :
String s = new String("TestString");
I understand how s refers to a string created dynamically. s is not an object in itself, but refers to one.
But I am not able to figure out what this means :
String s = "TestString";
Q1. If it would have been some primitive data type I would understand, but what does this signify for a class type ?
Q2. Is this kind of initialization allowed for user created classes as well ?
Java Level : Beginner
Q1. If it would have been some primitive data type I would understand, but what does this signify for a class type ?
In this case, "TestString" is a string literal. A string literal also serves as a reference to an instance of String. This is per the language specification, §3.10.5. So, in your particular case "TestString" is a reference to an instance of String, and you are assigning that same reference to your variable s.
Now, there are some rather special things about Strings that are referred to by literals. Two string literals with the same value (logically, as strings) always refer to the same instance of String. This is due to the "interning" of string literals.
However, when you say
String s = new String("TestString");
it is still the case that "TestString" refers to an instance of String, in fact to an instance in the string intern pool, but it is not the case that s refers to this same string. Instead, s is initialized to have its value equal to "TestString", but it is in fact a new reference. That is:
String s = new String("TestString");
String t = "TestString";
System.out.println(s == t);
This will print false.
Q2. Is this kind of initialization allowed for user created classes as well ?
No.
String s = "TestString";
Is the normal way to create a String. In fact when you do:
String s = new String("TestString");
What you're doing is create a string first, then passing it as an argument to new String(); So the question is not why the first one exists, but why the second one does. The answer is pretty subtle and you probably won't ever care: The first way creates a String literal that doesn't get garbage collected, and is shared on all the VM. The second one, instead, does. This means, for performance reasons, there are cases when you want to use the second form, like when working with very very large strings.
You can read more about it here:
http://kjetilod.blogspot.com.es/2008/09/string-constructor-considered-useless.html
From the Oracle Documentation:
The most direct way to create a string is to write:
String greeting = "Hello world!";
In this case, "Hello world!" is a string literal—a series of
characters in your code that is enclosed in double quotes. Whenever it
encounters a string literal in your code, the compiler creates a
String object with its value—in this case, Hello world!.
As with any other object, you can create String objects by using the
new keyword and a constructor.
Q1. If it would have been some primitive data type I would understand,
but what does this signify for a class type ?
No, this is special case, in case of String literals, String s = "someString" statement means we are referring to someString which is stored in string constant pool. someString will be an instance of String class but will be stored in string literal pool.
The special thing about String literal pool will be.
String s = "someString";
String s1 = "someString";
Here, s == s1' will returntrue` as they will refer to the same object in string literal pool.
String s2 = new String("someString");
String s3 = new String("someString");
Here, s2 == s3 will return false as both string will be created in non-constant pool memory.
You can find a good tutorial regarding strings here
http://www.thejavageek.com/2013/06/19/the-string-constant-pool/
http://www.thejavageek.com/2013/06/17/string-immutability-in-java/
Q2. Is this kind of initialization allowed for user created classes as
well ?
No we can't.

String with new keyword and direct assignment in java [duplicate]

This question already has answers here:
What is the difference between "text" and new String("text")?
(13 answers)
Closed 2 years ago.
String s="hi";
String s1=new String("hi");
In memory perspective, where are s and s1 stored? whether it is in heap memory or stack.
And s points "hi" and s1 points to memory location of where hi exists?
Please help?
Consider following
String s = "hi";
String s1 = new String("hi");
variable s will refer to the string literal hi that is referenced from String constant pool and if there are some more variables like s2 = "hi", then s and s2 will refer to same object.
String s1 = new String("hi");
This will create a new String at runtime.
In first case ,all the strnig literals are created when class is loaded in JVM
In seconds case, string objects are created when new String() is executed.
You can find a good tutorial about string constant pool at following link
http://www.thejavageek.com/2013/06/19/the-string-constant-pool/
String s="hi";
This statements creates the String object containing "hi" on the String pool.
String s1=new String("hi");
This statement creates a String object containing "hi" on the heap memory and a copy of it on StringPool (if "Hi" is not contained in stringPool).But here, S will point to the object on heap.
At class loading time, all String literals will be placed in pool. When you use new String("hi") an object will be created on heap. s and s1 are reference variables , it should reside in the method call stack ! The string literal "hi" will be handled by the JVM, by creating a String object on the heap, and having a reference to it from the String pool. The new operator merely takes the string object, whose reference is passed in the constructor, and create a new object. It just so happens that the string being passed to the constructor is a literal.
"hi" is a String literal. This gets created once in the String Constant Pool. In Java 7 that's in the Heap with other objects, but prior to that it was created in the Perm-Gen
String s = "hi";
String s1 = new String("hi");
new String("hi") creates a new String object on the heap, separate from the existing one.
s and s1 are references to the two separate objects. References themselves actually live on the stack, even though they point to objects in the heap.
s and s1 are just references to the strings, therefore they will be stored on the stack, unlike the string instances that are referenced by s and s1. In this case the value that s refers to will be put in the string pool whereas the value refered by s1 won't. Why? because the constructor of a string has been used to make that string. Only literals are pooled, and even if you chose those literals to be concatenations of other literals ( for example, if you have made String s2 = "h" + "i" then s and s2 would point to the same instance of a string that was stored in the string pool).
This leads to a little trap though: because pooled strings point to the same object it is tempting to use == operator instead of equals method to compare strings, which is just dangerous, because there are scenarios where == is the same as equals() but there are a lot more where == will have a different result than the equals() method.
Above answers are correct but shouldn't you use String *s1 = new String("hi") in place ofString s1 = new String("hi") ,as call to new will be returning a pointer to the string object.
I am fairly new to C++. Excuse me, if I am wrong.
PS: I am using the gcc version 4.4.7 20120313 (Red Hat 4.4.7-4) (GCC).
According to me when we create String using literal like String s="hello"
s object will reference the String "hello" that is stored in the String Constant pool.
If we will create the new String using New keyword like String s = new String("hello") then in this case two object is created. object s referenced the another object that is stored in the normal heap area and this object will referenced the String Hello that is stored in the String constant pool.
For more details please follow the link:-http://www.javatpoint.com/java-string

Categories