According to String#intern(), intern method is supposed to return the String from the String pool if the String is found in String pool, otherwise a new string object will be added in String pool and the reference of this String is returned.
So i tried this:
String s1 = "Rakesh";
String s2 = "Rakesh";
String s3 = "Rakesh".intern();
if ( s1 == s2 ){
System.out.println("s1 and s2 are same"); // 1.
}
if ( s1 == s3 ){
System.out.println("s1 and s3 are same" ); // 2.
}
I was expecting that s1 and s3 are same will be printed as s3 is interned, and s1 and s2 are same will not be printed. But the result is: both lines are printed. So that means, by default String constants are interned. But if it is so, then why do we need the intern method? In other words when should we use this method?
Java automatically interns String literals. This means that in many cases, the == operator appears to work for Strings in the same way that it does for ints or other primitive values.
Since interning is automatic for String literals, the intern() method is to be used on Strings constructed with new String()
Using your example:
String s1 = "Rakesh";
String s2 = "Rakesh";
String s3 = "Rakesh".intern();
String s4 = new String("Rakesh");
String s5 = new String("Rakesh").intern();
if ( s1 == s2 ){
System.out.println("s1 and s2 are same"); // 1.
}
if ( s1 == s3 ){
System.out.println("s1 and s3 are same" ); // 2.
}
if ( s1 == s4 ){
System.out.println("s1 and s4 are same" ); // 3.
}
if ( s1 == s5 ){
System.out.println("s1 and s5 are same" ); // 4.
}
will return:
s1 and s2 are same
s1 and s3 are same
s1 and s5 are same
In all the cases besides of s4 variable, a value for which was explicitly created using new operator and where intern method was not used on it's result, it is a single immutable instance that's being returned JVM's string constant pool.
Refer to JavaTechniques "String Equality and Interning" for more information.
On a recent project, some huge data structures were set up with data that was read in from a database (and hence not String constants/literals) but with a huge amount of duplication. It was a banking application, and things like the names of a modest set (maybe 100 or 200) corporations appeared all over the place. The data structures were already large, and if all those corp names had been unique objects they would have overflowed memory. Instead, all the data structures had references to the same 100 or 200 String objects, thus saving lots of space.
Another small advantage of interned Strings is that == can be used (successfully!) to compare Strings if all involved strings are guaranteed to be interned. Apart from the leaner syntax, this is also a performance enhancement. But as others have pointed out, doing this harbors a great risk of introducing programming errors, so this should be done only as a desparate measure of last resort.
The downside is that interning a String takes more time than simply throwing it on the heap, and that the space for interned Strings may be limited, depending on the Java implementation. It's best done when you're dealing with a known reasonable number of Strings with many duplications.
I want to add my 2 cents on using == with interned strings.
The first thing String.equals does is this==object.
So although there is some miniscule performance gain ( you are not calling a method), from the maintainer point of view using == is a nightmare, because some interned strings have a tendency to become non-interned.
So I suggest not to rely on special case of == for interned strings, but always use equals as Gosling intended.
EDIT: interned becoming non-interned:
V1.0
public class MyClass
{
private String reference_val;
...
private boolean hasReferenceVal ( final String[] strings )
{
for ( String s : strings )
{
if ( s == reference_val )
{
return true;
}
}
return false;
}
private void makeCall ( )
{
final String[] interned_strings = { ... init with interned values ... };
if ( hasReference( interned_strings ) )
{
...
}
}
}
In version 2.0 maintainer decided to make hasReferenceVal public, without going into much detail that it expects an array of interned strings.
V2.0
public class MyClass
{
private String reference_val;
...
public boolean hasReferenceVal ( final String[] strings )
{
for ( String s : strings )
{
if ( s == reference_val )
{
return true;
}
}
return false;
}
private void makeCall ( )
{
final String[] interned_strings = { ... init with interned values ... };
if ( hasReference( interned_strings ) )
{
...
}
}
}
Now you have a bug, that may be very hard to find, because in majority of cases array contains literal values, and sometimes a non-literal string is used. If equals were used instead of == then hasReferenceVal would have still continue to work. Once again, performance gain is miniscule, but maintenance cost is high.
Learn Java String Intern - once for all
Strings in java are immutable objects by design. Therefore, two string objects even with same value will be different objects by default. However, if we wish to save memory, we could indicate to use same memory by a concept called string intern. The below rules would help you understand the concept in clear terms:
String class maintains an intern-pool which is initially empty. This pool must guarantee to contain string objects with only unique values.
All string literals having same value must be considered same memory-location object because they have otherwise no notion of distinction. Therefore, all such literals with same value will make a single entry in the intern-pool and will refer to same memory location.
Concatenation of two or more literals is also a literal. (Therefore rule #2 will be applicable for them)
Each string created as object (i.e. by any other method except as literal) will have different memory locations and will not make any entry in the intern-pool
Concatenation of literals with non-literals will make a non-literal. Thus, the resultant object will have a new memory location and will NOT make an entry in the intern-pool.
Invoking intern method on a string object, either creates a new object that enters the intern-pool or return an existing object from the pool that has same value. The invocation on any object which is not in the intern-pool, does NOT move the object to the pool. It rather creates another object that enters the pool.
Example:
String s1=new String ("abc");
String s2=new String ("abc");
If (s1==s2) //would return false by rule #4
If ("abc" == "a"+"bc" ) //would return true by rules #2 and #3
If ("abc" == s1 ) //would return false by rules #1,2 and #4
If ("abc" == s1.intern() ) //would return true by rules #1,2,4 and #6
If ( s1 == s2.intern() ) //wound return false by rules #1,4, and #6
Note: The motivational cases for string intern are not discussed here. However, saving of memory will definitely be one of the primary objectives.
String literals and constants are interned by default.
That is, "foo" == "foo" (declared by the String literals), but new String("foo") != new String("foo").
you should make out two period time which are compile time and runtime time.for example:
//example 1
"test" == "test" // --> true
"test" == "te" + "st" // --> true
//example 2
"test" == "!test".substring(1) // --> false
"test" == "!test".substring(1).intern() // --> true
in the one hand,in the example 1,we find the results are all return true,because in the compile time,the jvm will put the "test" to the pool of literal strings,if the jvm find "test" exists,then it will use the exists one,in example 1,the "test" strings are all point to the same memory address,so the example 1 will return true.
in the other hand,in the example 2,the method of substring() execute in the runtime time,
in the case of "test" == "!test".substring(1),the pool will create two string object,"test"
and "!test",so they are different reference objects,so this case will return false,in the case of "test" == "!test".substring(1).intern(),the method of intern() will put the ""!test".substring(1)" to the pool of literal strings,so in this case,they are same reference objects,so will return true.
http://en.wikipedia.org/wiki/String_interning
string interning is a method of storing only one copy of each distinct string value, which must be immutable. Interning strings makes some string processing tasks more time- or space-efficient at the cost of requiring more time when the string is created or interned. The distinct values are stored in a string intern pool.
Interned Strings avoid duplicate Strings. Interning saves RAM at the expense of more CPU time to detect and replace duplicate Strings. There is only one copy of each String that has been interned, no matter how many references point to it. Since Strings are immutable, if two different methods incidentally use the same String, they can share a copy of the same String. The process of converting duplicated Strings to shared ones is called interning.String.intern() gives you the address of the canonical master String. You can compare interned Strings with simple == (which compares pointers) instead of equals which compares the characters of the String one by one. Because Strings are immutable, the intern process is free to further save space, for example, by not creating a separate String literal for "pot" when it exists as a substring of some other literal such as "hippopotamus".
To see more http://mindprod.com/jgloss/interned.html
String s1 = "Anish";
String s2 = "Anish";
String s3 = new String("Anish");
/*
* When the intern method is invoked, if the pool already contains a
* string equal to this String object as determined by the
* 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.
*/
String s4 = new String("Anish").intern();
if (s1 == s2) {
System.out.println("s1 and s2 are same");
}
if (s1 == s3) {
System.out.println("s1 and s3 are same");
}
if (s1 == s4) {
System.out.println("s1 and s4 are same");
}
OUTPUT
s1 and s2 are same
s1 and s4 are same
String p1 = "example";
String p2 = "example";
String p3 = "example".intern();
String p4 = p2.intern();
String p5 = new String(p3);
String p6 = new String("example");
String p7 = p6.intern();
if (p1 == p2)
System.out.println("p1 and p2 are the same");
if (p1 == p3)
System.out.println("p1 and p3 are the same");
if (p1 == p4)
System.out.println("p1 and p4 are the same");
if (p1 == p5)
System.out.println("p1 and p5 are the same");
if (p1 == p6)
System.out.println("p1 and p6 are the same");
if (p1 == p6.intern())
System.out.println("p1 and p6 are the same when intern is used");
if (p1 == p7)
System.out.println("p1 and p7 are the same");
When two strings are created independently, intern() allows you to compare them and also it helps you in creating a reference in the string pool if the reference didn't exist before.
When you use String s = new String(hi), java creates a new instance of the string, but when you use String s = "hi", java checks if there is an instance of word "hi" in the code or not and if it exists, it just returns the reference.
Since comparing strings is based on reference, intern() helps in you creating a reference and allows you to compare the contents of the strings.
When you use intern() in the code, it clears of the space used by the string referring to the same object and just returns the reference of the already existing same object in memory.
But in case of p5 when you are using:
String p5 = new String(p3);
Only contents of p3 are copied and p5 is created newly. So it is not interned.
So the output will be:
p1 and p2 are the same
p1 and p3 are the same
p1 and p4 are the same
p1 and p6 are the same when intern is used
p1 and p7 are the same
public static void main(String[] args) {
// TODO Auto-generated method stub
String s1 = "test";
String s2 = new String("test");
System.out.println(s1==s2); //false
System.out.println(s1==s2.intern()); //true --> because this time compiler is checking from string constant pool.
}
string intern() method is used to create an exact copy of heap string object in string constant pool. The string objects in the string constant pool are automatically interned but string objects in heap are not. The main use of creating interns is to save the memory space and to perform faster comparison of string objects.
Source : What is string intern in java?
As you said, that string intern() method will first find from the String pool, if it finds, then it will return the object that points to that, or will add a new String into the pool.
String s1 = "Hello";
String s2 = "Hello";
String s3 = "Hello".intern();
String s4 = new String("Hello");
System.out.println(s1 == s2);//true
System.out.println(s1 == s3);//true
System.out.println(s1 == s4.intern());//true
The s1 and s2 are two objects pointing to the String pool "Hello", and using "Hello".intern() will find that s1 and s2. So "s1 == s3" returns true, as well as to the s3.intern().
By using heap object reference if we want to get corresponding string constant pool object reference, then we should go for intern()
String s1 = new String("Rakesh");
String s2 = s1.intern();
String s3 = "Rakesh";
System.out.println(s1 == s2); // false
System.out.println(s2 == s3); // true
Pictorial View
Step 1:
Object with data 'Rakesh' get created in heap and string constant pool. Also s1 is always pointing to heap object.
Step 2:
By using heap object reference s1, we are trying to get corresponding string constant pool object referenc s2, using intern()
Step 3:
Intentionally creating a object with data 'Rakesh' in string constant pool, referenced by name s3
As "==" operator meant for reference comparison.
Getting false for s1==s2
Getting true for s2==s3
Hope this help!!
Related
This question already has answers here:
How do I compare strings in Java?
(23 answers)
What is the difference between "text" and new String("text")?
(13 answers)
Closed 3 years ago.
public class Test {
public static void main(String[] args)
{
String s1 = "HELLO";
String s2 = "HELLO";
System.out.println(s1 == s2); // true
}
}
But when I use :
public class Test {
public static void main(String[] args)
{
String s1 = new String("HELLO");
String s2 = new String("HELLO");
System.out.println(s1 == s2); // false
}
}
Can anybody please explain the difference here? Thankyou!
In the first example
String s1 = "HELLO";
String s2 = "HELLO";
the values of s1 and s2 are compile-time constants. Thus, the compiler does only generate a single String-object, holding the value "HELLO" and assings it to both s1 and s2. This is a special case of Common Subexpression Elimination, a well-known compiler optimization. Thus s1 == s2 returns true.
In the second example, two different Strings are constructed explicitly through new. Thus, they have to be separate objects per the semantics of new.
I created an Ideone demo a while back that highlights some cases that show this behaviour.
You can enforce that the same String is return by using String::intern():
String s1 = new String("HELLO").intern();
String s2 = new String("HELLO").intern();
System.out.println(s1 == s2); // will print "true";
Ideone demo
In case of String literal,before creating new Object in String Constant Pool ,JVM will check already same Object persist in SCP area or not if yes it will point to same object instead of creating new Object.Hence, below code s1 == s2 is true
String s1 = "HELLO";
String s2 = "HELLO";
System.out.println(s1 == s2); // true
but we are creating new object by using new keyword, it will create object in heap area, hence s1 and s2 are pointing to two different object, hence it is return false
== tests for reference equality (whether they are the same object).
.equals() tests for value equality (whether they are logically "equal").
from here How do I compare strings in Java?
== compares the objects reference pointer. When 2 objects are same exact object it will be true.
Instantiating a string using double quotes uses the string pool, creates a string once and reuses it.
Instantiating a string wit new always creates a brand new string.
== tests for reference equality (whether they are the same object).
First Case
System.out.println(s1 == s2); // true
Because you are comparing literals that are interned by the compiler and thus refer to the same object. 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 - are "interned" so as to share unique instances, using the method String.intern.
Second Case
System.out.println(s1 == s2); // false
You are comparing the Object reference which is different so you are getting false.
Please check https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.28
i first case u comparing two strings with its ASCII values. thats why...//true
and in second case you are comparing two functions/methods. thats why... //false
the first one is true because s1 and s2 refer to the same string literal in the method area, the memory references are the same. ( == checks just the references in string). when the same string literal is created more than once, only one copy of each distinct string value is stored.
the second one is false because s1 and s2 refer to two different objects in the heap. different objects always have different memory references.
Could you pls explain on the below code:
I know that == compares the reference and not the values .
But I am not clear what exactly is happening on the below code?
public class StringEquals {
public static void main(String args[])
{
String s1="AB";
String s2="AB"+"C";
String s3="A"+"BC";
if(s1==s2)
{
System.out.println("s1 and s2 are equal");
}
else
{
System.out.println("s1 and s2 are notequal");
}
if(s2==s3)
{
System.out.println("s2 and s3 are equal");
}
else
{
System.out.println("s2 and s3 are notequal");
}
if(s1==s3)
{
System.out.println("s1 and s3 are equal");
}
else
{
System.out.println("s1 and s3 are notequal");
}
}
}
In Java, == checks if two objects are exactly same thing, sometime it acts not what you think.
String s1 = new String("AB")
String s2 = new String("AB")
Although s1 and s2 have the same content, but s1 == s2 returns false. Because they have different reference, But s1 s2 have same value so s1.equals(s2) returns true
On my system, the code prints
s1 and s2 are notequal
s2 and s3 are equal
s1 and s3 are notequal
If your question is why, it has to do with how the Java compiler treats String literals.
Usually, Java will point all references to the same string literal to the same object, for efficiency. In the case of s2 and s3, the compiler appears to have realized that the result of the concatenation is the same string literal, so it assigned the references s2 and s3 to point at the same object in memory. That is why those two compare equal with ==.
Since s1 does not have the same value as s2 and s3, it will be assigned a different memory location, so the reference will not compare equal with ==.
In your code you will likely output System.out.println("s2 and s3 are equal");
This is due to string interning. When the string is a compile time constant the JVM sets all the references to identical strings to the same object. This is an efficiency saving and the java standard does not oblige the JVM to do so, it only allows it to. You should never rely on this behaviour.
Because at compile time it was known that both "AB"+"C" and "A"+"BC" will evaluate to "ABC" it was possible to set both s2 and s3 to refer to a single string in the string pool.
It goes without saying that even if this works in some cases it is a dangerous road to go down and strings should always be compared using string.equals(otherString)
if i create a string object as
String s=new String("Stackoverflow");
will String object created only in heap, or it also makes a copy in String constant pool.
Thanks in advance.
You only get a string into the constant pool if you call intern or use a string literal, as far as I'm aware.
Any time you call new String(...) you just get a regular new String object, regardless of which constructor overload you call.
In your case you're also ensuring that there is a string with contents "Stackoverflow" in the constant pool, by the fact that you're using the string literal at all - but that won't add another one if it's already there. So to split it up:
String x = "Stackoverflow"; // May or may not introduce a new string to the pool
String y = new String(x); // Just creates a regular object
Additionally, the result of a call to new String(...) will always be a different reference to all previous references - unlike the use of a string literal. For example:
String a = "Stackoverflow";
String b = "Stackoverflow";
String x = new String(a);
String y = new String(a);
System.out.println(a == b); // true due to constant pooling
System.out.println(x == y); // false; different objects
Finally, the exact timing of when a string is added to the constant pool has never been clear to me, nor has it mattered to me. I would guess it might be on class load (all the string constants used by that class, loaded immediately) but it could potentially be on a per-method basis. It's possible to find out for one particular implementation using intern(), but it's never been terribly important to me :)
In this case you are constructing an entirely new String object and that object won't be shared in the constant pool. Note though that in order to construct your new String() object you actually passed into it a String constant. That String constant is in the constants pool, however the string you created through new does not point to the same one, even though they have the same value.
If you did String s = "Stackoverflow" then s would contain a reference to the instance in the pool, also there are methods to let you add Strings to the pool after they have been created.
The new String is created in the heap, and NOT in the string pool.
If you want a newly create String to be in the string pool you need to intern() it; i.e.
String s = new String("Stackoverflow").intern();
... except of course that will return the string literal object that you started with!!
String s1 = "Stackoverflow";
String s2 = new String(s1);
String s3 = s2.intern();
System.out.println("s1 == s2 is " + (s1 == s2));
System.out.println("s2 == s3 is " + (s2 == s3));
System.out.println("s1 == s3 is " + (s1 == s3));
should print
s1 == s2 is false
s2 == s3 is false
s1 == s3 is true
And to be pedantic, the String in s is not the String that was created by the new String("StackOverflow") expression. What intern() does is to lookup the its target object in the string pool. If there is already a String in the pool that is equal(Object) to the object being looked up, that is what is returned as the result. In this case, we can guarantee that there will already be an object in the string pool; i.e. the String object that represents the value of the literal.
A regular java object will be created in the heap, and will have a reference s type of String. And, there will be String literal in String Constant Pool. Both are two different things.
My answer is YES!
Check the following code first:
String s0 = "Stackoverflow";
String s1 = new String("Stackoverflow");
String s2 = s1.intern();
System.out.println(s0 == s1);
System.out.println(s1 == s2 );
System.out.println(s0 == s2);
//OUTPUT:
false
false
true
s0 hold a reference in the string pool, while new String(String original) will always construct a new instance. intern() method of String will return a reference in the string pool with the same value.
Now go back to your question:
Will String object created only in heap, or it also makes a copy in String constant pool?
Since you already wrote a string constant "Stackoverflow" and pass it to your String constructor, so in my opinion, it has the same semantic as:
String s0 = "Stackoverflow";
String s1 = new String(s0);
which means there will be a copy in String constant pool when the code is evaluated.
But, if you construct the String object with following code:
String s = new String("StackoverflowSOMETHINGELSE".toCharArray(),0,13);
there won't be a copy of "Stackoverflow" in constant pool.
The code below should not print "Bye", since == operator is used to compare references, but oddly enough, "Bye" is still printed. Why does this happen? I'm using Netbeans 6.9.1 as the IDE.
public class Test {
public static void main(String [] args) {
String test ="Hi";
if(test=="Hi"){
System.out.println("Bye");
}
}
}
This behavior is because of interning. The behavior is described in the docs for String#intern (including why it's showing up in your code even though you never call String#intern):
A pool of strings, initially empty, is maintained privately by the class String.
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.
It follows that for any two strings s and t, s.intern() == t.intern() is true if and only if s.equals(t) is true.
All literal strings and string-valued constant expressions are interned. String literals are defined in ยง3.10.5 of the Java Language Specification.
So for example:
public class Test {
private String s1 = "Hi";
public static void main(String [] args) {
new Test().test();
System.exit(0);
}
public void test() {
String s2 ="Hi";
String s3;
System.out.println("[statics] s2 == s1? " + (s2 == s1));
s3 = "H" + part2();
System.out.println("[before interning] s3 == s1? " + (s3 == s1));
s3 = s3.intern();
System.out.println("[after interning] s3 == s1? " + (s3 == s1));
System.exit(0);
}
protected String part2() {
return "i";
}
}
Output:
[statics] s2 == s1? true
[before interning] s3 == s1? false
[after interning] s3 == s1? true
Walking through that:
The literal assigned to s1 is automatically interned, so s1 ends up referring to a string in the pool.
The literal assigned to s2 is also auto-interned, and so s2 ends up pointing to the same instance s1 points to. This is fine even though the two bits of code may be completely unknown to each other, because Java's String instances are immutable. You can't change them. You can use methods like toLowerCase to get back a new string with changes, but the original you called toLowerCase (etc.) on remains unchanged. So they can safely be shared amongst unrelated code.
We create a new String instance via a runtime operation. Even though the new instance has the same sequence of characters as the interned one, it's a separate instance. The runtime doesn't intern dynamically-created strings automatically, because there's a cost involved: The work of finding the string in the pool. (Whereas when compiling, the compiler can take that cost onto itself.) So now we have two instances, the one s1 and s2 point to, and the one s3 points to. So the code shows that s3 != s1.
Then we explicitly intern s3. Perhaps it's a large string we're planning to hold onto for a long time, and we think it's likely that it's going to be duplicated in other places. So we accept the work of interning it in return for the potential memory savings. Since interning by definition means we may get back a new reference, we assign the result back to s3.
And we can see that indeed, s3 now points to the same instance s1 and s2 point to.
Hard-coded Strings are compiled into the JVM's String Table, which holds unique Strings - that is the compiler stores only one copy of "Hi", so you are comparing that same object, so == works.
If you actually create a new String using the constructor, like new String("Hi"), you will get a different object.
There is a String cache in java. Where as in this case the same object is returned from the cache which hold the same reference.
The main reason for that is because the "Hi" is picked up from String Pool. The immutable object must have some sort of cache so it can perform better. So String class is immutable and it uses String Pool for basic cache.
In this case, "Hi" is in the String pool and all the String having values of "Hi" will have the same reference for String Pool.
According to String#intern(), intern method is supposed to return the String from the String pool if the String is found in String pool, otherwise a new string object will be added in String pool and the reference of this String is returned.
So i tried this:
String s1 = "Rakesh";
String s2 = "Rakesh";
String s3 = "Rakesh".intern();
if ( s1 == s2 ){
System.out.println("s1 and s2 are same"); // 1.
}
if ( s1 == s3 ){
System.out.println("s1 and s3 are same" ); // 2.
}
I was expecting that s1 and s3 are same will be printed as s3 is interned, and s1 and s2 are same will not be printed. But the result is: both lines are printed. So that means, by default String constants are interned. But if it is so, then why do we need the intern method? In other words when should we use this method?
Java automatically interns String literals. This means that in many cases, the == operator appears to work for Strings in the same way that it does for ints or other primitive values.
Since interning is automatic for String literals, the intern() method is to be used on Strings constructed with new String()
Using your example:
String s1 = "Rakesh";
String s2 = "Rakesh";
String s3 = "Rakesh".intern();
String s4 = new String("Rakesh");
String s5 = new String("Rakesh").intern();
if ( s1 == s2 ){
System.out.println("s1 and s2 are same"); // 1.
}
if ( s1 == s3 ){
System.out.println("s1 and s3 are same" ); // 2.
}
if ( s1 == s4 ){
System.out.println("s1 and s4 are same" ); // 3.
}
if ( s1 == s5 ){
System.out.println("s1 and s5 are same" ); // 4.
}
will return:
s1 and s2 are same
s1 and s3 are same
s1 and s5 are same
In all the cases besides of s4 variable, a value for which was explicitly created using new operator and where intern method was not used on it's result, it is a single immutable instance that's being returned JVM's string constant pool.
Refer to JavaTechniques "String Equality and Interning" for more information.
On a recent project, some huge data structures were set up with data that was read in from a database (and hence not String constants/literals) but with a huge amount of duplication. It was a banking application, and things like the names of a modest set (maybe 100 or 200) corporations appeared all over the place. The data structures were already large, and if all those corp names had been unique objects they would have overflowed memory. Instead, all the data structures had references to the same 100 or 200 String objects, thus saving lots of space.
Another small advantage of interned Strings is that == can be used (successfully!) to compare Strings if all involved strings are guaranteed to be interned. Apart from the leaner syntax, this is also a performance enhancement. But as others have pointed out, doing this harbors a great risk of introducing programming errors, so this should be done only as a desparate measure of last resort.
The downside is that interning a String takes more time than simply throwing it on the heap, and that the space for interned Strings may be limited, depending on the Java implementation. It's best done when you're dealing with a known reasonable number of Strings with many duplications.
I want to add my 2 cents on using == with interned strings.
The first thing String.equals does is this==object.
So although there is some miniscule performance gain ( you are not calling a method), from the maintainer point of view using == is a nightmare, because some interned strings have a tendency to become non-interned.
So I suggest not to rely on special case of == for interned strings, but always use equals as Gosling intended.
EDIT: interned becoming non-interned:
V1.0
public class MyClass
{
private String reference_val;
...
private boolean hasReferenceVal ( final String[] strings )
{
for ( String s : strings )
{
if ( s == reference_val )
{
return true;
}
}
return false;
}
private void makeCall ( )
{
final String[] interned_strings = { ... init with interned values ... };
if ( hasReference( interned_strings ) )
{
...
}
}
}
In version 2.0 maintainer decided to make hasReferenceVal public, without going into much detail that it expects an array of interned strings.
V2.0
public class MyClass
{
private String reference_val;
...
public boolean hasReferenceVal ( final String[] strings )
{
for ( String s : strings )
{
if ( s == reference_val )
{
return true;
}
}
return false;
}
private void makeCall ( )
{
final String[] interned_strings = { ... init with interned values ... };
if ( hasReference( interned_strings ) )
{
...
}
}
}
Now you have a bug, that may be very hard to find, because in majority of cases array contains literal values, and sometimes a non-literal string is used. If equals were used instead of == then hasReferenceVal would have still continue to work. Once again, performance gain is miniscule, but maintenance cost is high.
Learn Java String Intern - once for all
Strings in java are immutable objects by design. Therefore, two string objects even with same value will be different objects by default. However, if we wish to save memory, we could indicate to use same memory by a concept called string intern. The below rules would help you understand the concept in clear terms:
String class maintains an intern-pool which is initially empty. This pool must guarantee to contain string objects with only unique values.
All string literals having same value must be considered same memory-location object because they have otherwise no notion of distinction. Therefore, all such literals with same value will make a single entry in the intern-pool and will refer to same memory location.
Concatenation of two or more literals is also a literal. (Therefore rule #2 will be applicable for them)
Each string created as object (i.e. by any other method except as literal) will have different memory locations and will not make any entry in the intern-pool
Concatenation of literals with non-literals will make a non-literal. Thus, the resultant object will have a new memory location and will NOT make an entry in the intern-pool.
Invoking intern method on a string object, either creates a new object that enters the intern-pool or return an existing object from the pool that has same value. The invocation on any object which is not in the intern-pool, does NOT move the object to the pool. It rather creates another object that enters the pool.
Example:
String s1=new String ("abc");
String s2=new String ("abc");
If (s1==s2) //would return false by rule #4
If ("abc" == "a"+"bc" ) //would return true by rules #2 and #3
If ("abc" == s1 ) //would return false by rules #1,2 and #4
If ("abc" == s1.intern() ) //would return true by rules #1,2,4 and #6
If ( s1 == s2.intern() ) //wound return false by rules #1,4, and #6
Note: The motivational cases for string intern are not discussed here. However, saving of memory will definitely be one of the primary objectives.
String literals and constants are interned by default.
That is, "foo" == "foo" (declared by the String literals), but new String("foo") != new String("foo").
you should make out two period time which are compile time and runtime time.for example:
//example 1
"test" == "test" // --> true
"test" == "te" + "st" // --> true
//example 2
"test" == "!test".substring(1) // --> false
"test" == "!test".substring(1).intern() // --> true
in the one hand,in the example 1,we find the results are all return true,because in the compile time,the jvm will put the "test" to the pool of literal strings,if the jvm find "test" exists,then it will use the exists one,in example 1,the "test" strings are all point to the same memory address,so the example 1 will return true.
in the other hand,in the example 2,the method of substring() execute in the runtime time,
in the case of "test" == "!test".substring(1),the pool will create two string object,"test"
and "!test",so they are different reference objects,so this case will return false,in the case of "test" == "!test".substring(1).intern(),the method of intern() will put the ""!test".substring(1)" to the pool of literal strings,so in this case,they are same reference objects,so will return true.
http://en.wikipedia.org/wiki/String_interning
string interning is a method of storing only one copy of each distinct string value, which must be immutable. Interning strings makes some string processing tasks more time- or space-efficient at the cost of requiring more time when the string is created or interned. The distinct values are stored in a string intern pool.
Interned Strings avoid duplicate Strings. Interning saves RAM at the expense of more CPU time to detect and replace duplicate Strings. There is only one copy of each String that has been interned, no matter how many references point to it. Since Strings are immutable, if two different methods incidentally use the same String, they can share a copy of the same String. The process of converting duplicated Strings to shared ones is called interning.String.intern() gives you the address of the canonical master String. You can compare interned Strings with simple == (which compares pointers) instead of equals which compares the characters of the String one by one. Because Strings are immutable, the intern process is free to further save space, for example, by not creating a separate String literal for "pot" when it exists as a substring of some other literal such as "hippopotamus".
To see more http://mindprod.com/jgloss/interned.html
String s1 = "Anish";
String s2 = "Anish";
String s3 = new String("Anish");
/*
* When the intern method is invoked, if the pool already contains a
* string equal to this String object as determined by the
* 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.
*/
String s4 = new String("Anish").intern();
if (s1 == s2) {
System.out.println("s1 and s2 are same");
}
if (s1 == s3) {
System.out.println("s1 and s3 are same");
}
if (s1 == s4) {
System.out.println("s1 and s4 are same");
}
OUTPUT
s1 and s2 are same
s1 and s4 are same
String p1 = "example";
String p2 = "example";
String p3 = "example".intern();
String p4 = p2.intern();
String p5 = new String(p3);
String p6 = new String("example");
String p7 = p6.intern();
if (p1 == p2)
System.out.println("p1 and p2 are the same");
if (p1 == p3)
System.out.println("p1 and p3 are the same");
if (p1 == p4)
System.out.println("p1 and p4 are the same");
if (p1 == p5)
System.out.println("p1 and p5 are the same");
if (p1 == p6)
System.out.println("p1 and p6 are the same");
if (p1 == p6.intern())
System.out.println("p1 and p6 are the same when intern is used");
if (p1 == p7)
System.out.println("p1 and p7 are the same");
When two strings are created independently, intern() allows you to compare them and also it helps you in creating a reference in the string pool if the reference didn't exist before.
When you use String s = new String(hi), java creates a new instance of the string, but when you use String s = "hi", java checks if there is an instance of word "hi" in the code or not and if it exists, it just returns the reference.
Since comparing strings is based on reference, intern() helps in you creating a reference and allows you to compare the contents of the strings.
When you use intern() in the code, it clears of the space used by the string referring to the same object and just returns the reference of the already existing same object in memory.
But in case of p5 when you are using:
String p5 = new String(p3);
Only contents of p3 are copied and p5 is created newly. So it is not interned.
So the output will be:
p1 and p2 are the same
p1 and p3 are the same
p1 and p4 are the same
p1 and p6 are the same when intern is used
p1 and p7 are the same
public static void main(String[] args) {
// TODO Auto-generated method stub
String s1 = "test";
String s2 = new String("test");
System.out.println(s1==s2); //false
System.out.println(s1==s2.intern()); //true --> because this time compiler is checking from string constant pool.
}
string intern() method is used to create an exact copy of heap string object in string constant pool. The string objects in the string constant pool are automatically interned but string objects in heap are not. The main use of creating interns is to save the memory space and to perform faster comparison of string objects.
Source : What is string intern in java?
As you said, that string intern() method will first find from the String pool, if it finds, then it will return the object that points to that, or will add a new String into the pool.
String s1 = "Hello";
String s2 = "Hello";
String s3 = "Hello".intern();
String s4 = new String("Hello");
System.out.println(s1 == s2);//true
System.out.println(s1 == s3);//true
System.out.println(s1 == s4.intern());//true
The s1 and s2 are two objects pointing to the String pool "Hello", and using "Hello".intern() will find that s1 and s2. So "s1 == s3" returns true, as well as to the s3.intern().
By using heap object reference if we want to get corresponding string constant pool object reference, then we should go for intern()
String s1 = new String("Rakesh");
String s2 = s1.intern();
String s3 = "Rakesh";
System.out.println(s1 == s2); // false
System.out.println(s2 == s3); // true
Pictorial View
Step 1:
Object with data 'Rakesh' get created in heap and string constant pool. Also s1 is always pointing to heap object.
Step 2:
By using heap object reference s1, we are trying to get corresponding string constant pool object referenc s2, using intern()
Step 3:
Intentionally creating a object with data 'Rakesh' in string constant pool, referenced by name s3
As "==" operator meant for reference comparison.
Getting false for s1==s2
Getting true for s2==s3
Hope this help!!