intern() behaving differently in Java 6 and Java 7

2019-01-07 06:36发布

class Test {
    public static void main(String...args) {
        String s1 = "Good";
        s1 = s1 + "morning";
        System.out.println(s1.intern());
        String s2 = "Goodmorning";
        if (s1 == s2) {
            System.out.println("both are equal");
        }
    }
}

This code produces different outputs in Java 6 and Java 7. In Java 6 the s1==s2 condition returns false and in Java 7 the s1==s2 returns true. Why?

Why does this program produces different output in Java 6 and Java 7?

9条回答
Bombasti
2楼-- · 2019-01-07 06:49

The result code dependents runtime:

class Test {
     public static void main(String... args) {
        String s1 = "Good";
        s1 = s1 + "morning";
        System.out.println(s1 == s1.intern()); // Prints true for jdk7, false - for jdk6.
    }
}

If you write like this:

class Test {
     public static void main(String... args) {
        String s = "GoodMorning";
        String s1 = "Good";
        s1 = s1 + "morning";
        System.out.println(s1 == s1.intern()); // Prints false for both jdk7 and jdk6.
    }
}

the reason is ' ldc #N ' (Load string from constant pool) and String.intern() both will use StringTable in hotspot JVM. For detail I wrote a pool english article: http://aprilsoft.cn/blog/post/307.html

查看更多
小情绪 Triste *
3楼-- · 2019-01-07 06:51

In jdk6: String s1="Good"; creates a String object "Good" in constant pool.

s1=s1+"morning"; creates another String object "morning" in constant pool but this time actually JVM do: s1=new StringBuffer().append(s1).append("morning").toString();.

Now as the new operator creates an object in heap therefore the reference in s1 is of heap not constant pool and the String s2="Goodmorning"; creates a String object "Goodmorning" in constant pool whose reference is stored in s2.

Therefore, if(s1==s2) condition is false.

But what happens in jdk7?

查看更多
疯言疯语
4楼-- · 2019-01-07 06:56

there are mainly 4 ways to compare string:

  1. "== operator": it just compares the reference variable of the string object. So it might give you unexpected results depending upon how you have created the string i.e. using String class's constructor or simply by using double quote as both get memory differently(in heap and pool respectively).
  2. "equals(Object) method": this is method of object class and is OVERLOADED by string class. It compares whole string and IS CASE SENSITIVE.
  3. "equalsIgnoreCase(String) method": this is method of string class and compares whole string and IS NOT CASE SENSITIVE.
  4. "compares(String) method": compare both strings character by character and return their difference if the returned value is 0, this means strings are equal.
查看更多
该账号已被封号
5楼-- · 2019-01-07 06:58

Let's omit unnecessary details from the example:

class Test {
    public static void main(String... args) {
        String s1 = "Good";
        s1 = s1 + "morning";
        System.out.println(s1 == s1.intern()); // Prints true for jdk7, false - for jdk6.
    }
}

Let's consider String#intern as a black box. Based on a few test cases run, I would conclude that implementation is as following:

Java 6:
if the pool contains object equals to this, then return reference to that object, else create new string (equal to this), put to the pool, and return reference to that created instance.

Java 7:
if the pool contains object equals to this, then return reference to that object, else put this to the pool, and return this.

Neither Java 6 nor Java 7 breaks the contract of the method.

It seems that new intern method behavior was a result of the fix of this bug: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6962931.

查看更多
成全新的幸福
6楼-- · 2019-01-07 07:00

Whenever you are comparing between two String, don't use == and use eqauls() becaue you are comparing objects not references:

string1.equals(string2);
查看更多
啃猪蹄的小仙女
7楼-- · 2019-01-07 07:02

FIRST CASE:

In the first code snipped you are actually adding three Strings in the Pool of Strings. 1. s1 = "Good"
2. s1 = "Goodmorning" (after concatenating) 3. s2 = "Goodmorining"

While doing if(s1==s2), the objects are same but reference as different hence it is false.

SECOND CASE:

In this case you are using s1.intern(), which implies that 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.

  1. s1 = "Good"
  2. s1 = "Goodmorning" (after concatenating)
  3. For String s2="Goodmorning", new String is not added to the pool and you get reference of existing one for s2. Hence if(s1==s2) returns true.
查看更多
登录 后发表回答