0

This is the piece of code I used from the SCJP book. I understand that == compares the memory location of the objects to find the equality and .equals compares the hashcode to determine the equality.

My question is in the below snippet, in the overrided equals method we compare :

(((Moof)o).getMoofValue()) == this.getMoofValue()

in the above code, does the == compare the memory location of the string value? If it does then it should be false. But it returns true. How does the == work here?

public class EqualsTest {

    public static void main(String args[]){
        Moof one = new Moof("a");
        Moof two = new Moof("a");
        if(one.equals(two)){
            System.out.println("Equal");
        }
        else{
            System.out.println("Not Equal");
        }
    }
}



    public class Moof {
        private String moofValue;
        public Moof(String i){
            this.moofValue = i;
        }
        public String getMoofValue(){
            return this.moofValue;
        }
        public boolean equals(Object o){
            if((o instanceof Moof) && (((Moof)o).getMoofValue()) == this.getMoofValue()){
                return true;
            }
            return false;
        }
    }
Alexis C.
  • 91,686
  • 21
  • 171
  • 177
Arun
  • 153
  • 1
  • 1
  • 8
  • for primitives "==" compares "their value" for non-primitives "==" compares the references... here, you are comparing 2 Strings with "==", so basically you are comparing references.. and BTW equals() compares references by default... It doesnt compare hashCode. – TheLostMind Jan 16 '14 at 06:47
  • 3
    `equals()` does not "compare the hashcode" ... it compares whatever the method is written to compare. – Brian Roach Jan 16 '14 at 06:48
  • ".equals compares the hashcode to determine the equality" - I would be quite surprised to see a class that does this. Even in the rare cases where it would actually work, it wouldn't be efficient. – user2357112 Jan 16 '14 at 06:48
  • Aside from that, the code you post is **broken** because it's not comparing `String`s correctly. It's using `==` which compares *reference values* – Brian Roach Jan 16 '14 at 06:48
  • Thanks for the quick response. But String is not a primitive. That is what I compare in the above code. – Arun Jan 16 '14 at 06:49
  • Because both the objects have same value for `moofValue`. And since it is a string literal "a", its interned. And both the references are pointing to same memory location. – Aman Arora Jan 16 '14 at 06:51
  • @Arun String literals in java are pooled. `"a" == "a"` will evaluate to `true`. `new String("a") == new String("a")` will not. This is why you *must* use `.equals()` See the answers to comparing strings Q – Brian Roach Jan 16 '14 at 06:51

4 Answers4

1

The "a" string literals are interned. Each "a" is the same string in memory, so they compare equal with ==. Note that you can't rely on this for strings in general. If you did the following:

    Moof two = new Moof("aa".substring(1));

the strings would be considered != to each other.

user2357112
  • 260,549
  • 28
  • 431
  • 505
1
(Moof)o).getMoofValue()) == this.getMoofValue()) 

here..You are still comparing references to the same String object in the String pool. Because String literals are interned automatically.

Edit :

public class TestClass {

    String s;

    TestClass(String s) {
        this.s = s;
    }

    public static void main(String[] args) {

        String s1 = new String("a");
        String s2 = new String("a");
        System.out.println(s1 == s2);

        TestClass t1 = new TestClass("a");
        TestClass t2 = new TestClass("a"); 
        System.out.println(t1 == t2);      // here you are comparing t1 with t2, not t1.s with t2.s so you get false... 
        System.out.println(t1.s == t2.s); // t1.s and t2.s refer to the same "a", so you get true.

     TestClass t3 = new TestClass(s1);
     TestClass t4 = new TestClass(s2);
     System.out.println(t3.s == t4.s);      // false because s1 and s2 are 2 different references. 
    }

}
O/P : 
false
false
true
false
TheLostMind
  • 35,966
  • 12
  • 68
  • 104
  • Hi, Thanks for the response. So my understanding is == compares the values for primitive and String literals, but for objects it compares the reference values. Correct me if I am wrong. – Arun Jan 16 '14 at 07:13
  • @Arun == check is the strings are the same instance (just as it does for other objects). However, the specifications says that string literals must refer to the same object. So "a" == "a" evaluates to true while "a" == new String("a") evaluates to false. – Roger Lindsjö Jan 16 '14 at 07:34
  • 1
    `==` does **exactly one thing**; it compares two values. In the case of primitives it compares the primitive values. In the case of object references it compares the reference values. Strings are *not* special. – Brian Roach Jan 16 '14 at 07:45
  • @Arun- "String literals " are also objects. They are placed in a seperate place in the memory known as String Pool which is part of the heap... In case of Strings also, "==" checks for references, not values... – TheLostMind Jan 17 '14 at 06:17
1

You are right that == compares if the references point to the same object. So, two different objects would evaluate to false with == even if equals() would evaluate to true.

S the following code

(((Moof)o).getMoofValue()) == this.getMoofValue()

checks if the objects are the same. However, in Java two equal string constants that are known at compile time must reference the same string object. Looking at

Moof one = new Moof("a");
Moof two = new Moof("a");

We could view this as

String theValue = "a";
Moof one = new Moof(theValue);
Moof two = new Moof(theValue);

However, making a new string must return a new object so you can try

Moof one = new Moof(new String("a"));
Moof two = new Moof(new String)"a");

which would cause the equality to evaluate to false. More specific example below:

String a1 = "a";
String a2 = "a";
String a3 = new String("a");
System.out.println(a1 == a2); // true
System.out.println(a1 == a3); // false

Equals does normally not use hashCode to check for equality but it could be used to make a quick check if more comparisons are needed. The hashCode is a numerical indicator of the object, which if you implemented a PersonId class could be a numerical value of the country phone prefix and age of the person. So a 27 year old person from Sweden would get hash code 4627. Now, when checking if two PersonId refers to the same person you might have to do a lot of comparisons, but if the hashCode is not the same then no more comparisons are needed (since either the country or age is different and the PersonIds must refer to different persons).

The hashCode is used in structures such as HashMap as a value for knowing which "bucket" to store the object in.

Roger Lindsjö
  • 11,330
  • 1
  • 42
  • 53
  • Thanks Roger for your response. I understand this now. Appreciate you helping hand. – Arun Jan 16 '14 at 07:24
0

I understand that == compares the memory location of the objects to find the equality and .equals compares the hashcode to determine the equality.

No it doesn't. .equals() does whatever the guy who wrote it wrote. In the case of Object.equals(), it returns the result of ==. hashCode() has nothing to do with it.

in the above code, does the == compare the memory location of the string value?

Yes, you've already said that.

If it does then it should be false. But it returns true. How does the == work here?

Because both occurrences of "a" are pooled to the same value, with the same address.

user207421
  • 305,947
  • 44
  • 307
  • 483