user11935191
user11935191

Reputation:

Why java object comparison is failing with both '==' and .equals() method?

I am comparing same objects using == and equals() method but both of them are failing. I tried four combinations as follows. Please someone guide where I am making mistake.

public class Question {

int rollNo;
String name;

Question(int rollNo, String name) {
    this.rollNo = new Integer(rollNo);
    this.name = new String(name);
}

public int getRollNo() {
    return new Integer(rollNo);
}

public void setRollNo(int rollNo) {
    if(rollNo>0) this.rollNo = rollNo;
}

public String getName() {
    return new String(name);
}

public void setName(String name) {
    if(name!=null) this.name = name;
}

public static void main(String[] args) {
    Question obj1 = new Question(123, "Student1");
    Question obj2 = new Question(123, "Student1");
    Question obj3 = new Question(456, "Student2");

            // All if conditions are evaluating to false
    if(obj1 == obj2) System.out.println("Equal objects 1 and 2 using ==");
    if(obj1.equals(obj2)) System.out.println("Equal objects 1 and 2 using equals()");
    if(obj1 == new Question(123, "Student1")) System.out.println("Equal objects 1 and 2 using == and new");
    if((new Question(123, "Student1")).equals(obj2)) System.out.println("Equal objects 1 and 2 using equals() and new");        
}

}

I welcome suggestions on my code quality too as I have just started coding.

Upvotes: 0

Views: 1022

Answers (2)

Stephen C
Stephen C

Reputation: 719659

It fails with == because the Question objects are different objects. (The == operator for reference types tests to see if the references are for the same object.)

It fails with equals because you are using the Object::equals(Object) method. That method is specified to have the same meaning as ==.

If you want Question::equals(Object) to behave differently, you need to override the method inherited from Object by adding a method like this:

    @Override
    public boolean equals(Object other) {
        // implement this according to the spec to give the equality
        // semantics you need
    }

An actual implementation might look like this:

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj instanceof Question) {
            Question other = (Question) obj;
            return this.rollNo == other.rollNo &&
                   this.name.equals(other.name);
        } else {
            return false;
        }
    }

I noticed some other problems in your code. For example:

    Question(int rollNo, String name) {
        this.rollNo = new Integer(rollNo);
        this.name = new String(name);
    }
  1. The constructor should probably be public.
  2. Since this.rollNo is declared as an int, creating an Integer and assigning that is pointless ... and inefficient. What will happen is the Integer will be unboxed to get its value, and the object will then be thrown away. Just assign rollNo to this.rollNo.
  3. If you really need to obtain an Integer instance explicitly, the correct way to do it is to use Integer.valueOf(int). That makes uses of a built-in cache of Integer objects.
  4. Creating a String with new String(name) is unnecessary and inefficient. Strings are immutable. There is not need to copy them. Certainly, not here.

Upvotes: 2

Matt U
Matt U

Reputation: 5118

A class is a reference type, so when checking equality, it will be false any time you're not comparing two references to the same object. All the values in the objects may be the same, but they are not the same object.

If you want to be able to compare two instances of your Question class like this, you'll need to override equals and getHashCode. See here: https://www.geeksforgeeks.org/overriding-equals-method-in-java/

Upvotes: 1

Related Questions