2

I have been overrided the hashcode and equals to find the value which have same startDate and closingDate. And I am getting the similar hash code for duplicate objects. When equating these objects I am getting boolean "false". In my understanding object==object compares the reference of the object, even though the reference are same; the code is returning false. Can you please help me to understand what is the issue. I have posted my code below:

Hashcode & equals Method

public int hashCode() {
    final int prime = 31; 
    int result = 1;
    result = prime * result + ((this.startDate == null) ? 0 : this.startDate.getDate());
    result = prime * result + ((this.closingDate == null) ? 0 : this.closingDate.getDate());
    return result;
}

public boolean equals(Object customer) {
    if(customer == null || customer.getClass()!= this.getClass())
        return false;

    return this==customer;
}

Main.java

public class HashQuestion {
    public static void main(String[]args) {
        Map<Integer, Customer> custMap = new HashMap<Integer, Customer>();
        custMap.put(1, createCustomer(1, new Date()));
        custMap.put(2, createCustomer(2, new Date()));
        custMap.put(3, createCustomer(3, new Date()));
        Customer checkCustomer = createCustomer(1, new Date());
        for (Customer cust : custMap.values()) {

            if (cust.equals(checkCustomer)) {
                System.out.println("Duplicate No: "+cust.getCustId()+ ", Start date: " + 
                        cust.getStartDate().toString() + " End date: " +cust.getClosingDate().toString());
            }
            else
                System.out.println("No: "+cust.getCustId()+ ", Start date: " + 
                    cust.getStartDate().toString() + " End date: " +cust.getClosingDate().toString());
        } 
    }

    @SuppressWarnings("deprecation")
    static Customer createCustomer(int number, Date date) {
        Date closeDate = new Date(); 
        Date startDate = new Date(); 
        closeDate.setDate(date.getDate() + number);
        startDate.setDate(date.getDate() - number);
        return new Customer(number, number+1, startDate, closeDate);
    }
}

Output:

No: 1, Start date: Wed Jun 20 19:42:46 IST 2018 End date: Fri Jun 22 19:42:46 IST 2018
No: 2, Start date: Tue Jun 19 19:42:46 IST 2018 End date: Sat Jun 23 19:42:46 IST 2018
No: 3, Start date: Mon Jun 18 19:42:46 IST 2018 End date: Sun Jun 24 19:42:46 IST 2018

checkCustomer object reference: Customer@643

Object references (which is in Map): [Customer@643, Customer@625, Customer@607]

Here object1 is having same reference as checkCustomer obj. However obj==checkCustomer, returns false.

Ojasvi Bhargava
  • 312
  • 1
  • 2
  • 10
Vishwa Dany
  • 327
  • 2
  • 16

5 Answers5

2

Change from this:

Map<Integer, Customer> custMap = new HashMap<Integer, Customer>();
custMap.put(1, createCustomer(1, new Date()));
custMap.put(2, createCustomer(2, new Date()));
custMap.put(3, createCustomer(3, new Date()));
Customer checkCustomer = createCustomer(1, new Date()); //This is a different reference

To this:

Map<Integer, Customer> custMap = new HashMap<Integer, Customer>();
Customer checkCustomer = createCustomer(1, new Date());
custMap.put(1, checkCustomer); //Now this is the same reference
custMap.put(2, createCustomer(2, new Date()));
custMap.put(3, createCustomer(3, new Date()));

You are creating 4 different customers, this will create three.

purring pigeon
  • 4,141
  • 5
  • 35
  • 68
1

If you create a NEW object (using "new") the objects will always have a different address in the heap and therefore == will always return false if you compare them.

e.g.

Integer i1 = new Integer(1);
Integer i2 = new Integer(1);

i1.equals(i2) --> true
i1 == i2 --> false

In your equals method in the last line you make an reference compare (==) which you should never do in objects (only primitives and enums). If you are using an IDE (e.g. eclipse) you can generate the equals and hashcode methods using fields identifying your object instances.

Rainer
  • 761
  • 5
  • 20
  • From your reply i am able to understand that object_reference_id and object_hashcode are different. == Will compare the reference_id not the hashcode. Please let me know if this is incorrect – Vishwa Dany Jun 21 '18 at 15:20
  • That is correct. HashCode is "only" used from classes utilizing it (e.g. HashMap). – Rainer Jun 23 '18 at 20:07
0

You are creating two different objects via

return new Customer(number, number+1, startDate, closeDate);

So the comparison has to be false. If you want to compare the attributes of the object you have to implement that in your equals method.

It should to look more like that:

public boolean equals(Object customer) {
    if(customer == null || customer.getClass()!= this.getClass())
        return false;

    return this.getCustId()==customer.getCustId();
}
0

So lets break my answer into two parts :

(i) How the object references evaluated to be same ---- java.lang.Object provides an implementation of the toString method, the string that it returns is class name followed by an “at” sign (@) and the unsigned hexadecimal representation of the hash code, for example . In you case checkCustomer object reference: Customer@643 Object references (which is in Map): [Customer@643, Customer@625, Customer@607]

The first element in the map and check reference are completely different objects but the toString() method has computed them to same is because of hash collision and your custom hashCode() method has contributed to it ,

public int hashCode() {
    final int prime = 31; 
    int result = 1;
    result = prime * result + ((this.startDate == null) ? 0 : this.startDate.getDate());
    result = prime * result + ((this.closingDate == null) ? 0 : this.closingDate.getDate());
    return result;
}

which is completely fine because no hash function exists without collision

2) Even if the references are same why your equals(Object o) implemention didn't return true ---

Lets check your equals method:

public boolean equals(Object customer) {
    if(customer == null || customer.getClass()!= this.getClass())
        return false;

    return this==customer;
}

Do note that " == " operator checks if two references point to same object. In your case its not hence it returned false .

PS: As a rule of thumb please consider overriding toString() method .Check essay Item10 in EffectiveJava Second editon.

Debapriya Biswas
  • 1,079
  • 11
  • 23
0

As per my analysis on this question, "==" compares the memory address, not the object reference. Following stackoverflow questions helps me to understand this:

What is the difference between == vs equals() in Java?

Memory address of variables in Java

Let me know if the understanding is incorrect

Thanks everyone

Vishwa Dany
  • 327
  • 2
  • 16