Java对象的hashcode()方法

本文详细介绍了Java中hashCode方法的基本概念,包括其在哈希表中的作用、重写规则及注意事项。同时,文章对比分析了基本类型与引用类型在hashCode计算上的差异,并提供了实例代码说明equals与hashCode的关系。
一、hashcode简介

注意:
  public int hashCode()方法返回对象的哈希码值。 这种方法是为了散列表,如HashMap。
     第一条: 只要在执行Java应用程序时多次在同一个对象上调用该方法, hashCode方法必须始终返回相同的整数。
     第二条: 如果根据equals(Object)方法两个对象相等,则在两个对象中的每个对象上调用hashCode方法必须产生相同的整数结果。
     第三条: 不要求如果两个对象根据equals(java.lang.Object)方法不相等,那么在两个对象中的每个对象上调用hashCode方法必须产生不同的整数结果。 但是,程序员应该意识到,为不等对象生成不同的整数结果可能会提高哈希表的性能,减少哈希碰撞
  由类别Object定义的hashCode方法确实为不同对象返回不同的整数,未重写方法时一般通过将对象的内部地址转换为整数来实现,重写后一般通过将对象的内容转换为整数来实现
   哈希表: 哈希表是结合了直接寻址和链式寻址两种方式,所需要的就是将需要加入哈希表的数据首先计算哈希值,其实就是预先分个组,然后再将数据挂到分组后的链表后面,随着添加的数据越来越多,分组链上会挂接更多的数据,同一个分组链上的数据必定具有相同的哈希值,java中的hash函数返回的是int类型的,也就是说,最多允许存在2^32个分组,也是有限的,所以出现相同的哈希码就不稀奇了


总结:
  1、hashcode相等,equals不一定相等,这也是哈希碰撞产生的原因。
  2、equals相等,若没有重写equals方法,则为同一个对象,其对应的hashcode相等,若重写了equals方法,但是没有重写hashcode方法,则不一定相等,要是重写了hashcode方法则相等。


二、包装类型

  包装类型全都重写了hashcode方法
    1)、Byte、Short、Integer、Long对应的hashcode方法,均是返回原值

        Integer a = 1;
        System.out.println(a.hashCode());//1
        Byte b = 2;
        System.out.println(b.hashCode());//2
        Short d = 3;
        System.out.println(d.hashCode());//3
        Long e = 4L;
        System.out.println(e.hashCode());//4

重写后的方法:Byte、Short、Integer、Long方法类似

  @Override
    public int hashCode() {
        return Short.hashCode(value);
    }
    
    public static int hashCode(short value) {
        return (int)value;
    }

    2)、Character对应的hashcode方法,返回的是字符对应的ASCII码值(包含0-9、a-z、A-Z以及一些字符)

        Character f = '!';
        System.out.println(f.hashCode());//33

重写后的方法

  @Override
    public int hashCode() {
        return Character.hashCode(value);
    }

    public static int hashCode(char value) {
        return (int)value;
    }

    3)、Double、Float对应的hashcode方法,返回的是经过计算的值,与地址无关,也和数据类型无关

        Double g = 2.0;
        System.out.println(g.hashCode());//1073741824
        Double g1 = 2.0;
        System.out.println(g.hashCode() == g1.hashCode());//true
        Float h = 2.0F;
        System.out.println(h.hashCode());//1073741824

重写后的方法

  @Override
    public int hashCode() {
        return Double.hashCode(value);
    }
    
     public static int hashCode(double value) {
        long bits = doubleToLongBits(value);
        return (int)(bits ^ (bits >>> 32));
    }
    
       public static long doubleToLongBits(double value) {
        long result = doubleToRawLongBits(value);
        // Check for NaN based on values of bit fields, maximum
        // exponent and nonzero significand.
        if ( ((result & DoubleConsts.EXP_BIT_MASK) ==
              DoubleConsts.EXP_BIT_MASK) &&
             (result & DoubleConsts.SIGNIF_BIT_MASK) != 0L)
            result = 0x7ff8000000000000L;
        return result;
    }

    4)、Boolean对应的hashcode方法,返回的是固定的两个值,true返回1231,false返回1237

        Boolean i = true;
        System.out.println(i.hashCode());//1231

重写后的方法

      @Override
    public int hashCode() {
        return Boolean.hashCode(value);
    }

    
    public static int hashCode(boolean value) {
        return value ? 1231 : 1237;
    }
    


二、引用数据类型

  分析实例解释

public class People {
    private String name;
    private int age;

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public People() {
    }

    public People(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        People people = (People) o;
        return age == people.age &&
                Objects.equals(name, people.name);
    }

    @Override
    public int hashCode() {

        return Objects.hash(name, age);
    }
}

        Set<People> set = new HashSet<>();
        set.add(xiaoer);
        set.add(xiaomi);

如果想完整的使用HashSet类那么最少要重写equals()和hashCode()方法。重写hashCode() 用于获得元素的存储位置,重写equals() 用于在两个元素的位置相同的时候比较两个元素是否相等。
重写后的方法。

     @Override
        public int hashCode() {
    
            return Objects.hash(name, age);
        }
    
    
          public static int hash(Object... values) {
            return Arrays.hashCode(values);
        }
    
    
        public static int hashCode(Object a[]) {
        if (a == null)
            return 0;

        int result = 1;

        for (Object element : a)
            result = 31 * result + (element == null ? 0 : element.hashCode());

        return result;
    }
    
        People xiaomi = new People("小米",4);
        People xiaoer = new People("小米",4);
        System.out.println(xiaoer.hashCode() == xiaomi.hashCode());//重写后,ture
        System.out.println(xiaoer.hashCode() == xiaomi.hashCode());//重写前,false
    

<think> 根据用户需求,用户希望了解如何重写Java对象hashCode()和equals()方法。首先需要明确重写这两个方法的原因和规则,然后给出具体的实现步骤和示例。 根据引用内容,重写equals()hashCode()方法的主要原因包括: 1. 当需要根据对象的内容而非引用判断相等性时(引用[3])。 2. 为了保证在集合类(如HashSet、HashMap)中正确工作(引用[3][4])。 3. 遵守equals和hashCode之间的一致性约定:如果两个对象equals相等,则它们的hashCode必须相等;但hashCode相等不代表equals一定相等(引用[2][4])。 重写equals()方法的步骤: 1. 使用==检查是否引用同一对象。 2. 使用instanceof检查类型是否匹配。 3. 将参数转换为正确类型。 4. 根据需要比较的字段进行判断(基本类型用==,引用类型用equals())。 重写hashCode()方法的步骤: 1. 选择一个初始的非零奇数作为基础值(如17)。 2. 对于每个关键字段,计算其哈希码,然后合并到整体哈希码中(使用31作为乘数)。 3. 合并规则:result = 31 * result + (field == null ? 0 : field.hashCode()); 示例代码: ```java public class Person { private String name; private int age; @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof Person)) return false; Person person = (Person) o; return age == person.age && Objects.equals(name, person.name); } @Override public int hashCode() { return Objects.hash(name, age); } } ``` 注意事项: - 使用Objects.hash()简化hashCode实现(如示例所示)。 - 确保equals()方法满足自反性、对称性、传递性和一致性(引用[3])。 - 在集合中使用时,若修改了参与equals/hashCode计算的字段,可能导致无法正确检索(所以这类对象最好设计为不可变)。 相关问题生成: 1. 为什么重写equals()方法必须同时重写hashCode()方法? 2. 在重写equals()方法时需要注意哪些原则? 3. 如何设计一个不可变类并正确重写equals()hashCode()方法? 4. 使用Objects.hash()方法有什么优点和缺点? 5. 如果只重写equals()而不重写hashCode()会有什么后果? </think> ### Java对象`hashCode()`和`equals()`方法的重写方法 #### 一、为什么需要重写? 1. **对象相等性判断** Java默认的`Object.equals()`比较对象**内存地址**。若需根据**字段值**判断逻辑相等性(如两个`Person`对象的`name`和`age`相同即视为相等),则需重写`equals()`[^3]。 2. **集合操作的正确性** `HashSet`、`HashMap`等集合依赖`hashCode()`确定存储位置,并用`equals()`验证对象是否真正相等。若不重写,可能导致: - 逻辑相等的对象被集合视为不同 - 对象存入集合后无法正确检索[^3][^4]。 3. **遵守一致性规约** **必须**同时重写两个方法,并满足: ```markdown 若 obj1.equals(obj2) == true → 必有 obj1.hashCode() == obj2.hashCode() ``` 反之则不成立(哈希冲突时,不同对象可能有相同哈希值)[^2][^4]。 --- #### 二、重写步骤与示例 ##### 1. **重写`equals()`方法** ```java @Override public boolean equals(Object o) { // 1. 检查是否为同一对象 if (this == o) return true; // 2. 检查类型是否匹配 if (o == null || getClass() != o.getClass()) return false; // 3. 类型转换 Person person = (Person) o; // 4. 关键字段值比较 return age == person.age && Objects.equals(name, person.name); } ``` **关键点**: - 参数必须是`Object`类型 - 使用`Objects.equals()`避免空指针(如比较`name`字段) - 比较所有参与逻辑相等性的字段 ##### 2. **重写`hashCode()`方法** ```java @Override public int hashCode() { // 使用Objects.hash()自动组合字段哈希值 return Objects.hash(name, age); } ``` **原理**: `Objects.hash()`内部实现为: ```java int result = 31 * (字段1哈希值) + 字段2哈希值; // 31是质数,可减少哈希冲突[^5] ``` --- #### 三、完整示例(`Person`类) ```java public class Person { private String name; private int age; // 构造方法、getter/setter省略 @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Person person = (Person) o; return age == person.age && Objects.equals(name, person.name); } @Override public int hashCode() { return Objects.hash(name, age); } } ``` --- #### 四、验证重写是否正确 ```java Person p1 = new Person("Alice", 30); Person p2 = new Person("Alice", 30); // 应输出 true System.out.println(p1.equals(p2)); // 应输出 true System.out.println(p1.hashCode() == p2.hashCode()); // 存入HashSet测试 Set<Person> set = new HashSet<>(); set.add(p1); System.out.println(set.contains(p2)); // 应输出true ``` --- #### 五、注意事项 1. **不可变字段原则** 参与`equals()`/`hashCode()`计算的字段应**不可变**(如`final`)。若字段被修改,可能导致对象存入集合后无法检索[^3]。 2. **避免`NullPointerException`** 使用`Objects.equals(field1, field2)`替代`field1.equals(field2)`。 3. **性能优化** 在`equals()`中优先比较**计算成本低**的字段(如基本类型),或先用`hashCode`快速筛选: ```java if (this.hashCode() != obj.hashCode()) return false; ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值