Java中如何重载equsals和hashCode方法,示例和提示

6 篇文章 0 订阅

How to override equals and hashCode method in Java - Example, Tips

Override equals and hashCode in Java
Equals and hashCode in Java are two fundamental method which is declared in Object class and part or core Java library. equals() method is used to compare Objects for equality while hashCode is used to generate an integer code corresponding to that object. equals and hashCode has used extensively in Java core library like they are used while inserting and retrieving Object in HashMap, see how HashMap works in Java for full story, equals method is also used to avoid duplicates on HashSet and other Set implementation and every other place where you need to compare Objects. Default implementation of equals() class provided by java.lang.Object  compares memory location and only return true if two reference variable  are pointing to same memory location i.e. essentially they are same  object. Java recommends to override equals and hashCode  method if equality is going to be define by logical way or via some  business logic and many classes in Java standard library does override  it e.g. Stringoverrides equals,  whose implementation of equals() method return true if content of two String objects are exactly same. Integer wrapper class overrides equals to perform numerical comparison etc.
Since HashMap and Hashtable in Java relies on equals() and hashCode() method for comparing keys and values, Java provides following rules to override equals method Java. As per following rule equals method in Java should be:

1) Reflexive : Object must be equal to itself.
2) Symmetric : if a.equals(b) is true then b.equals(a) must be true.
3) Transitive : if a.equals(b) is true and b.equals(c) is true then c.equals(a) must be true.
4) Consistent : multiple invocation of equals()  method must result same value until any of properties are modified. So  if two objects are equals in Java they will remain equals until any of  there property is modified.
5) Null comparison : comparing any object to null must be false and should not result in NullPointerException. For example a.equals(null) must be false, passing unknown object, which could be null,  to equals in Java is is actually a Java coding best practice to avoid NullPointerException in Java.


Equals and hashCode contract in Java
And equals method in Java must follow its contract with hashCode method in Java as stated below.

1) If two objects are equal by equals() method then there hashcode must be same.
2) If two objects are not equal by equals() method then there hashcode could be same or different.

So this was the basic theory about equals method in Java now we are going to discuss the approach on how to override equals() method, yes I know you all know this stuff :) but I have seen some of equals() code which can be improved by following correct approach. For illustration purpose we will see an example of Person class and discuss How to write equals() method in Java for that class.

Steps to Override equals method in Java

Here is my approach for overriding equals method in Java. This is based on standard approach most of Java programmer follows while writing equals method in Java.

1) Do this check -- if yes then return true.
2) Do null check -- if yes then return false.
3) Do the instanceof check,  if instanceof return false than return false from equals in Java , after some research I found that instead of instanceof we can use getClass() method for type identification because instanceof check returns true for subclass also, so its not strictly equals comparison until required by business logic. But instanceof check is fine if your class is immutable and no one is going to sub class it. For example we can replace instanceof check by below code

if ((obj == null ) || (obj. getClass () != this. getClass ()))
        return false ;

4) Type cast the object; note the sequence instanceof check must be prior to casting object.

5)  Compare individual attribute starting with numeric attribute because  comparing numeric attribute is fast and use short circuit operator for  combining checks.  If first field does not match, don't try to match  rest of attribute and return false. It’s also worth to remember doing null check on individual attribute before calling equals() method on them recursively to avoid NullPointerExceptionduring equals check in Java.

Code Example of overriding equals method in Java
equals and hashCode method in Java example tutorialLet’s  see a code example based on my approach of overriding equals method in  Java as discussed in above paragraph and hashCode method is generated by  Eclipse IDE, see my post   5 tips to override hashCode in Java for detailed example and explanation of overriding hashCode.

/**
 * Person class with equals and hashcode implementation in Java
 * @author Javin Paul
 */

public class Person {
    private int id ;
    private String firstName ;
    private String lastName ;

    public int getId () { return id ; }
    public void setId ( int id ) { this. id = id ; }

    public String getFirstName () { return firstName ; }
    public void setFirstName ( String firstName ) { this. firstName = firstName ; }

    public String getLastName () { return lastName ; }
    public void setLastName ( String lastName ) { this. lastName = lastName ; }

    @ Override
    public boolean
equals ( Object obj ) {
        if (obj == this ) {
            return true ;
        }
        if (obj == null || obj. getClass () != this. getClass ()) {
            return false ;
        }

        Person guest = (Person ) obj ;
        return id == guest. id
                && (firstName == guest. firstName
                     || (firstName != null && firstName. equals (guest. getFirstName ())))
                && (lastName == guest. lastName
                     || (lastName != null && lastName . equals (guest. getLastName ()))) ;
    }
   
    @ Override
    public int
hashCode () {
        final int prime = 31 ;
        int result = 1 ;
        result = prime * result
                + ((firstName == null ) ? 0 : firstName. hashCode ()) ;
        result = prime * result + id ;
        result = prime * result
                + ((lastName == null ) ? 0 : lastName. hashCode ()) ;
        return result ;
    }
   
}

If you look above method we are first checking for " this" check which is fastest available check for equals method then we are verifying  whether object is null  or not and object is of same type or not. only after verifying type of  object we are casting it into desired object to  avoid any ClassCastException in  Java. Also while comparing individual attribute we are comparing  numeric attribute first using short circuit operator to avoid further  calculation if its already unequal and doing null check on member attribute to avoid NullPointerException.
           
           

Common Errors while overriding equals in Java

Though equals() and hashcode() method are defined in Object class along with wait, notify and notifyAll,  and one of fundamental part of Java programming I have seen many programmers making mistake while writing equals() method in Java. I recommend all Java programmer who has just started programming to write couple of equals and hashcode  method for there domain or value object to get feel of it. Here I am  listing some of common mistakes I have observed on various equals method  in Java, if you like to learn more about common mistakes in Java  programming then see my post Don’t use float and double for monetary calculation and Mixing static and non static synchronized method. Now let’s see common mistakes by Java programmers while overriding equals in Java :

1) Instead of overriding equals() method programmer overloaded it.
This is the most common error I have seen while overriding equals method in Java. Syntax of equals method defined in Object class is public boolean equals(Object obj) but many people unintentionally overloads equals method in Java by writing public boolean equals(Person obj), instead of using Object as argument they use there class name. This error is very hard to detect because of static binding.  So if you call this method in your class object it will not only  compile but also execute correctly but if you try to put your object in  collection e.g. ArrayList and call contains() method which is based on equals() method in Java it will not able to detect your object. So beware of it. This question is also a frequently asked question in Java interviews as part of Overloading vs Overriding in Java as how do you prevent this from happening ? Thankfully alongwith Generics, Enum, autoboxing and varargs Java 5 also introduces @Override annotation which can be used to tell compiler that you are overriding a method and than compiler will be able to detect this error during compile time. Consistently using @Override annotation is also a best practice in Java.


2) Second mistake I have seen while overriding equals() method is not doing null check for member variables which ultimately results in NullPointerException in Java during equals() invocation. For example in above code correct way of calling equals() method of member variable is after doing null check as shown below:

firstname == guest. firstname || (firstname != null && firstname. equals (guest. firstname ))) ;


3) Third common mistake is not overriding hashCode method in Java and only overriding equals() method .You must have to override both equals() and hashCode() method in Java , otherwise your value object will not be able to use as key object in HashMap because working of HashMap is based on equals() and hashCode to read more see , How HashMap works in Java.

4) Last common mistake programmer make while overriding equals() in Java is not keeping equals() and compareTo() method consistent which is a non formal requirement in order to obey contract of Set to avoid duplicates. SortedSet implementation like TreeSet uses compareTo to compare two objects like String and if compareTo() and equals()  will not be consistent than TreeSet will allow duplicates which will  break Set contract of not having duplicates. To learn more about this  issue see my post Things to remember while overriding compareTo in Java

Writing JUnit tests for equals method in Java
Its good coding practice  to write JUnit test cases to test your equals and hashCode method. Here  is my approach for writing JUnit test case for equals method in Java. I  will write test cases to check equals behavior, contract of equals and  hasCode method and properties of equals method in Java on different  circumstances. You can also JUnit4 annotation to write JUnit testcases, than you don’t need to use test prefix on test method, just use @Test annotations.

testReflexive() this method will test reflexive nature of equals() method in Java.

testSymmeteric() this method will verify symmetric nature of equals() in Java.

testNull() this method will verify null comparison and will pass if equals method returns false.

testConsistent() should verify consistent nature of equals method in Java.

testNotEquals()  should verify if two object which are not supposed to equals is  actually not equal, having negative test cases in test suite is  mandatory.

testHashCode() will verify that if two objects are equal by equals() method in Java then there hashcode must be same. This is an important test if you are thinking to use this object as key in HashMap or Hashtable

5 Tips on writing equals method in Java
Here are some tips to implement equals and hashCode method in Java, this will help you to do it correctly and with ease:

1) Most of the IDE like NetBeans, Eclipse and IntelliJ IDEA provides support to generate equals() and hashcode() method. In Eclipse do the right click-> source -> generate hashCode() and equals().

2)  If your domain class has any unique business key then just comparing  that field in equals method would be enough instead of comparing all the  fields e.g. in case of our example if "id" is unique for every Person and by just comparing id we can identify whether two Person are equal or not.

3) While overriding hashCode in Java makes sure you use all fields which have been used in equals method in Java.

4) String and Wrapper classes like Integer, Float and Double override equals method but StringBuffer doesn’t override it.

5) Whenever possible try to make your fields immutable by using final variables in Java, equals method based on immutable fields are much secure than on mutable fields.

That’s  about equals and hashCode in Java, I am reiterating this but its  imperative for a Java programmer to be able to write equals , hashCode,  compareTo method by hand. It is not just useful for learning purpose but  to clare any coding exercise during Java interviews. Writing code for  equals and hashCode is very popular programming interview questions now  days.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值