11

I learned that it is from the devil to test String equality with == instead of String.equals(), because every String was a reference to its own object.

But if i use something like

System.out.println("Hello" == "Hello");

it prints true.

Why?

Zeemee
  • 10,486
  • 14
  • 51
  • 81
  • 1
    Have a look at http://stackoverflow.com/questions/1091045/is-it-good-practice-to-use-java-lang-string-intern. They also discuss this issue. – ewernli Dec 07 '09 at 08:18
  • Please post an example that shows how "this works now". –  Dec 07 '09 at 08:18
  • How funny this came up - I was reversing {string == null ? "" : string} - all my tests passed, but when strings started being read from the database... – Stephen Dec 07 '09 at 08:28

3 Answers3

25

It doesn't. It's still a bad thing to do - you'll still be testing reference equality instead of value equality.

public class Test
{
    public static void main(String[] args)
    {
        String x = "hello";
        String y = new String(x);
        System.out.println(x == y); // Prints false
    }
}

If you're seeing == testing "work" now then it's because you genuinely have equal references. The most common reason for seeing this would probably be due to interning of String literals, but that's been in Java forever:

public class Test
{
    public static void main(String[] args)
    {
        String x = "hello";
        String y = "hel" + "lo"; // Concatenated at compile-time
        System.out.println(x == y); // Prints true
    }
}

This is guaranteed by section 3.10.5 of the Java Language Specification:

Each string literal is a reference (§4.3) to an instance (§4.3.1, §12.5) of class String (§4.3.3). String objects have a constant value. 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.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
3

It hasn't changed. However, the Java Compiler uses string.intern() to make sure that identical strings in source code compile to same String object. If however you load a String from a File or Database it will not be the same object, unless you force this using String.intern() or some other method.

It is a bad idea, and you should still use .equals()

Nick Fortescue
  • 43,045
  • 26
  • 106
  • 134
  • 1
    Manually interning String objects is risky because they can never be un-interned or garbage collected. One could easily consume all of the available memory that way. – Adriaan Koster Dec 07 '09 at 09:05
  • @Adriaan - unreachable interned Strings are garbage collected. This was apparently implemented in JDK 1.2. – Stephen C Dec 07 '09 at 10:43
1

Look, this is a tricky concept.

There is a difference between:

// These are String literals
String a = "Hiabc";
String b = "abc";
String c = "abc";

and

// These are String objects.
String a = new String("Hiabc");
String b = new String("abc");
String c = new String("abc"); 

If your strings were objects, i.e.,

String b = new String("abc");
String c = new String("abc");

Then, two different objects would have been created in the String pool at two different memory locations and doing

b == c  

would have resulted false.

But since your String b and String c are literals,

b == c  

results true. This is because two different objects were not created. And both a and b are pointing to same String in the stack memory.

This is the difference. You are right, == compares for memory location. And that is the reason,

a.substring(2, 5) == b; // a,substring(2, 5) = "abc" which is at the location of b, and
b == c // will be true, coz both b and c are literals. And their values are compared and not memory locations.

In order to have two separate Strings with same values but at different locations in the String pool and NOT stack memory, you need to create String objects as shown above.

So,

a.substring(2, 5) == b; // and
b == c; // will be false. as not both are objects. Hence are stored on separate memory locations on the String pool.

you have to use

a.substring(2, 5).equals(b);
b.equals(c);

in case of objects.

Aditya Singh
  • 2,343
  • 1
  • 23
  • 42