zoukankan      html  css  js  c++  java
  • 使用hashCode()和equals()方法

    在这篇文章中,我将指出我对hashCode()和equals()方法的理解。我将讨论它们的默认实现以及如何正确地覆盖它们。我还将使用Apache Commons包中的实用工具类来实现这些方法。

    hashCode()和equals()方法已经在Object类中定义,而Object类是所有Java对象的父类。因为这个原因,所有的Java对象从Object类继承了这些方法的默认实现。

       本文中的章节:

      hashCode()和equals()用法

      重写默认行为

      用Apache Commons Lang重写equals()和hashCode()

      需要记住的重要的事项

      在ORM中使用时要注意的地方

    hashCode()equals()方法的用法

    hashCode()方法用于获取给定对象的唯一的整数。当这个对象需要存储在哈希表这样的数据结构时,这个整数用于确定桶的位置。默认情况下,对象的hashCode()方法返回对象所在内存地址的整数表示。

    equals()方法用来简单验证两个对象的相等性。默认实现只检查两个对象的对象引用,以验证它们的相等性。

     

    重写默认行为

    通常情况下,类一切运行的都很好,根本不需要重写它们,但是有时应用程序需要更改某些对象的默认行为。

    让我们举一个例子,比如有一个应用程序拥有员工对象。让我们创建一个尽可能简单的员工类:

    public class Employee
    {
        private Integer id;
        private String firstname;
        private String lastName;
        private String department;
     
        public Integer getId() {
            return id;
        }
        public void setId(Integer 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;
        }
        public String getDepartment() {
            return department;
        }
        public void setDepartment(String department) {
            this.department = department;
        }
    }

    上面的员工类有一些非常基本的属性和访问方法。现在考虑一个简单的情况,您需要比较两个员工对象。

    public class EqualsTest {
        public static void main(String[] args) {
            Employee e1 = new Employee();
            Employee e2 = new Employee();
     
            e1.setId(100);
            e2.setId(100);
     
            //Prints false in console
            System.out.println(e1.equals(e2));
        }
    }

    不用猜,以上方法将输出“false”。但是,这两个对象现实生活中代表同一雇员。在实际应用程序中,必须返回true。

    要实现正确的行为,我们需要如下重载equal方法:

    public boolean equals(Object o) {
        if(o == null)
        {
            return false;
        }
        if (o == this)
        {
            return true;
        }
        if (getClass() != o.getClass())
        {
            return false;
        }
         
        Employee e = (Employee) o;
        return (this.getId() == e.getId());
         
    }

    把这个方法添加到你的员工,开始运行EqualTest,将打印true。

    这就完了吗?还没有。让我们以不同的方式再次测试上面修改过的员工类。

    import Java.util.HashSet;
    import Java.util.Set;
     
    public class EqualsTest
    {
        public static void main(String[] args)
        {
            Employee e1 = new Employee();
            Employee e2 = new Employee();
     
            e1.setId(100);
            e2.setId(100);
     
            //Prints 'true'
            System.out.println(e1.equals(e2));
     
            Set<Employee> employees = new HashSet<Employee>();
            employees.add(e1);
            employees.add(e2);
             
            //Prints two objects
            System.out.println(employees);
        }
    }

    上面的类在第二个打印语句中打印两个对象。如果员工对象已经相等,在一个Set集合中应该只存在一个对象, HashSet中该只有一个实例才对,毕竟对象指的是同一名员工。哪里出现了问题??

    问题出现在我们没有重写第二个重要的方法hashCode()。Java文档说,如果重写equals()方法,然后你必须重写hashCode()方法。因此,让我们在员工类中添加另一个方法。

    @Override
    public int hashCode()
    {
        final int PRIME = 31;
        int result = 1;
        result = PRIME * result + getId();
        return result;
    }

    一旦在雇员类中添加了上述方法,第二个语句就开始在第二个语句中只打印单个对象,从而验证了e1和e2的真正相等性。

    Apache Commons Lang 重写equals()hashCode()

    Apache Commons提供两个优秀的实用类 HashCodeBuilderEqualsBuilder用于生成hashCode和测试相等性的代码。下面是它们的使用:

    import org.apache.commons.lang3.builder.EqualsBuilder;
    import org.apache.commons.lang3.builder.HashCodeBuilder;
    public class Employee
    {
        private Integer id;
        private String firstname;
        private String lastName;
        private String department;
        public Integer getId() {
            return id;
        }
        public void setId(Integer 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;
        }
        public String getDepartment() {
            return department;
        }
        public void setDepartment(String department) {
            this.department = department;
        }
        @Override
        public int hashCode()
        {
            final int PRIME = 31;
            return new HashCodeBuilder(getId()%2==0?getId()+1:getId(), PRIME).toHashCode();
        }
        @Override
        public boolean equals(Object o) {
        if (o == null)
           return false;
            
        if (o == this)
           return true;
            
        if (o.getClass() != getClass())
           return false;
         
        Employee e = (Employee) o;
         
        return new EqualsBuilder().
                  append(getId(), e.getId()).
                  isEquals();
        }
    }

    或者,用代码编辑器自动生成,它们必然能够为您生成一些良好的代码。例如,Eclipse IDE选项, 在类上右键 >> source > Generate hashCode() and equals() … 会为你生成一个很好的实现。

                                                      

    需要记住的重要事项

    1) 始终使用一个对象的相同属性来生成hashCode()和equals()方法。在我们的例子中,我们使用了员工id。

    2) equals()必须一致(如果对象不被修改,那么它必须返回相同的值)。

    3) 每当a.equals(b),那么a.hashCode()和b. hashCode()必须相等。

    4) 如果重写一个,则应重写另一个。

    ORM中使用时需要注意的地方

    如果你正在处理一个ORM,确保hashCode()和equals()中始终使用getters,不要直接使用字段。这是因为在ORM中,偶尔字段被延迟加载,直到调用它们的getter方法时才可用。

    例如我们的员工类,如果我们使用e1.id = = e2.id。id字段非常可能是懒加载。因此,在这种情况下,一个可能是零或null,从而导致不正确的行为。

    但如果采用e1.getid() == e2.getid(),我们可以肯定,即使是懒加载,调用getter将首先让字段加载正确。

    这就是我关于hashCode()和equals()方法所知道的,希望它会帮助有的人。

    如果你觉得,我遗漏了什么或错误的地方,请留下评论。我会再次更新这篇文章来帮助别人。

    Happy Learning !!

  • 相关阅读:
    由zImage生成uImage 分类: arm-linux-Ubuntu 2013-07-22 16:29 274人阅读 评论(0) 收藏
    让UltraEdit成为java编译器 分类: JAVA 2013-07-22 16:29 372人阅读 评论(0) 收藏
    JAVA的helloworld 分类: JAVA 2013-07-22 16:29 395人阅读 评论(0) 收藏
    windowsXP下搭建JAVA环境教程 分类: JAVA 2013-07-22 16:29 494人阅读 评论(0) 收藏
    ap module omap4460 分类: arm-linux-Ubuntu 2013-07-22 16:29 460人阅读 评论(0) 收藏
    Pandaboard ES编译bootloader、xloader、内核、以及安卓系统 分类: arm-linux-Ubuntu 2013-07-22 16:29 367人阅读 评论(0) 收藏
    Bootloader Project 分类: arm-linux-Ubuntu 2013-07-22 16:29 327人阅读 评论(0) 收藏
    嵌入式Linux引导过程之1.5——从BootRom到Xloader 分类: arm-linux-Ubuntu 2013-07-22 16:29 281人阅读 评论(0) 收藏
    嵌入式Linux引导过程之1.6——Xloader的Xloader_Entry 分类: arm-linux-Ubuntu 2013-07-22 16:29 305人阅读 评论(0) 收藏
    1047. Student List for Course (25)
  • 原文地址:https://www.cnblogs.com/keeplearnning/p/7011250.html
Copyright © 2011-2022 走看看