5

Possible Duplicate:
intern() behaving differently in Java 6 and Java 7

While doing example for this question

I noticed a strange behaviour of intern() method when I call intern() method on String thereafter I can use == operator for the Original String.

JavaDoc of intern() method:

Returns a canonical representation for the string object. 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.

Above Javadoc does not say that the orginal string gets changed. So why this program prints okay when test is the input.

import java.util.Scanner;

public class Test {
    public static void main(String[] args) {
        Scanner user_input = new Scanner(System.in);
        String username;
        System.out.print("username: ");
        username = user_input.next();
        // Even if I do not assign returned string for comparison still it compares
        // okay else it does not compare
        username.intern();
        if (username == "test") {
            System.out.println("okay");
        }
        else {
            System.out.println("not okay");
        }
    }
}
Community
  • 1
  • 1
Amit Deshpande
  • 19,001
  • 4
  • 46
  • 72
  • 1
    The `intern()` call *should not* be able to influence the result of the test below. – Joachim Sauer Sep 05 '12 at 06:39
  • 1
    @JoachimSauer interestingly it does. Just tried it with the latest Java7. – Thomas Jungblut Sep 05 '12 at 06:41
  • Tried with java 6 and prints "not okay". – dcernahoschi Sep 05 '12 at 06:45
  • 1
    @ThomasJungblut: indeed, I just verified it with Java 7 as well (Java 6 prints "not okay" as expected). A possible explanation is that Java 7 builds the constant pool lazily, that could result in the in-code `"test"` effectively using the user-provided `"test"` String instance. – Joachim Sauer Sep 05 '12 at 06:46
  • The only relevant noted change in Java 7 I could find was [this RFE](http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6962931). A comment also notes the effect described herein, but it's not discussed further. – Joachim Sauer Sep 05 '12 at 06:48

3 Answers3

3

String.intern() returns the intern()ed String. This is because a method cannot change a reference passed to it.

So why this program prints okay when test is the input.

It prints okay because the intern()ed string is the first time this String is seen so it becomes the one String literal for "test". It is not the String which is changed, but the object which is used for "test" which is changed.

Try instead.

String te = "te", st = "st";
// "test".length();
String username = te + st;
username.intern();
System.out.println("String object the same is: "+ (username == "test"));

In this case, the output in Java 7 update 7 is

String object the same is: test

but run this on Java 6 update 32 or uncomment the line so "test" is seen first and you get.

String object the same is: false
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • But it is changing original string reference. I am using JDK7. – Amit Deshpande Sep 05 '12 at 07:24
  • 1
    What you are suggesting is impossible in Java for any method so, no it is not. – Peter Lawrey Sep 05 '12 at 07:26
  • @AmitD Added an example to demonstrate the difference. It is the String literal which is changed, not your `username` string. – Peter Lawrey Sep 05 '12 at 07:31
  • I assume that (in addition to the RFE linked in the comments and the duplicate candidate) a change in Java 7 is that string literals are searched/instantiated (more) lazily now. I was under the impression that Java loaded all relevant String literals of a class at load time ('though I have no references for this). – Joachim Sauer Sep 05 '12 at 08:07
  • @JoachimSauer Good point, have noted that Java 6 doesn't do this. – Peter Lawrey Sep 05 '12 at 08:10
2

str.intern() checks to see if there is already the same object in String pool and if so, reuses it.

Chris
  • 5,584
  • 9
  • 40
  • 58
  • 1
    That is correct, however the returned reference should be the pooled string. It should not change the reference from within the method. – Thomas Jungblut Sep 05 '12 at 06:48
0

Below line give you the input form user.

    username = user_input.next();

After that you are calling username.intern(); which returns the String literal of username
Now in your condition statement

if (username == "test") 

your variable username contain your String literal object from string pool and "test" is also a String literal so jvm is going to give you same reference of String test which is already created for username that means username and "test" are the same object. And in java == operated check reference for the object so in this case it will return true thats why its prints okay

Sumit Singh
  • 15,743
  • 6
  • 59
  • 89