对象的哈希值

对象的哈希值

  • 就是一个十进制整数。是通过Object类的hashCode()方法获得:int hashCode();

  • 默认Object类的hashCode的方法返回的哈希值是该对象在内存中的地址值。

  • 哈希值是对象存储到哈希表的重要依据。

哈希表的存储过程

  • 哈希表的存储过程(存取原理):每存入一个新的元素都要走以下五步

    • (1)调用对象的hashCode()方法,获得要存储元素的哈希值。

    • (2)将哈希值与表的长度(即数组的长度)进行求余运算得到一个整数值,该值就是新元素要存放的位置(即是索引值)。

      • 如果索引值对应的位置上没有存储任何元素,则直接将元素存储到该位置上。

      • 如果索引值对应的位置上已经存储了元素,则执行第3步。

    • (3)遍历该位置上的所有旧元素,依次比较每个旧元素的哈希值和新元素的哈希值是否相同。

      • 如果有哈希值相同的旧元素,则执行第4步。

      • 如果没有哈希值相同的旧元素,则执行第5步。

    • (4)比较新元素和旧元素的地址是否相同

      • 如果地址值相同则用新的元素替换老的元素。停止比较。

      • 如果地址值不同,则新元素调用equals方法与旧元素比较内容是否相同。

        • 如果返回true,用新的元素替换老的元素,停止比较。

        • 如果返回false,则回到第3步继续遍历下一个旧元素。

    • (5)说明没有重复,则将新元素存放到该位置上并让新元素记住之前该位置的元素。

问题:为什么存储字符串的时候,字符串内容相同的只存储了一个呢?
  • 通过查看add方法的源码,我们知道这个方法底层依赖 两个方法:hashCode()和equals()。

  • 步骤:

  • 首先比较哈希值

  • 如果相同,继续走,比较地址值或者走equals()

  • 如果不同,就直接添加到集合中

按照方法的步骤来说:

  • 先看hashCode()值是否相同

  • 相同:继续走equals()方法

  • 返回true: 说明元素重复,就不添加

  • 返回false:说明元素不重复,就添加到集合

  • 不同:就直接把元素添加到集合

  • 如果类没有重写这两个方法,默认使用Object()的方法。

  • 而String类重写了hashCode()和equals()方法,所以,它就可以把内容相同的字符串去掉。只留下一个。

    public static void main(String[] args) {
        
        // 创建集合对象
          HashSet<String> hs = new HashSet<String>();

          // 创建并添加元素
          hs.add("hello");
          hs.add("world");
          hs.add("java");
          hs.add("world");
          hs.add("hello");
          hs.add("world");
          hs.add("java");
          hs.add("world");

          print(hs);

    }

    public static <E> void print(Collection<E> link) {
        // 遍历
        for (E s : link) {
            System.out.println(s);
        }

        System.out.println("--------------------------");

         // 遍历集合,获取得到每一个元素
         Iterator<E> it = link.iterator();
         while (it.hasNext()) {
         E s = it.next();
         System.out.println(s);
         }
         System.out.println("--------------------------");
    }

### Java 对象 `hashCode` 的计算方式及原理 #### 1. 基本概念 在 Java 中,`hashCode()` 是定义于根类 `Object` 的方法之一。它的主要作用是为对象生成一个整数值(即哈希码),以便支持基于哈希的数据结构(如 `HashMap`, `HashSet` 等)。通过合理的哈希算法设计,可以显著提高这些数据结构的操作效率。 #### 2. 默认实现 如果开发者未重写 `hashCode()` 方法,则会使用来自 `Object` 类的默认实现。这种情况下,返回的是由 JVM 自动生成的一个与内存地址相关的整数[^1]。然而,默认实现通常不适用于实际业务场景中的复杂对象比较需求。 #### 3. 自定义 `hashCode` 实现原则 当创建自定义类时,若需要将其实例放入集合框架中(尤其是依赖哈希机制的部分),则应遵循以下原则来覆盖 `hashCode()` 和 `equals()` 方法: - **一致性**:只要对象的内容保持不变,多次调用其 `hashCode()` 应始终返回相同的值。 - **分布均匀性**:不同对象产生的哈希值应当尽可能分散开,减少冲突概率。 #### 4. 使用工具简化开发过程 现代编程实践中推荐利用现有库辅助完成高质量的 `hashCode` 函数编写工作。例如: ##### (a) 利用 JDK 提供的功能 从 Java 7 开始引入了静态实用程序类 `Objects` 下面的 `hash()` 方法,它允许传入多个字段并自动组合成最终结果。下面是一个例子展示如何简便地构建学生实体类的哈希逻辑[^2]: ```java import java.util.Objects; public class Student { private String name; private int age; private String gender; private String[] hobbies; @Override public int hashCode() { return Objects.hash(name, age, gender, hobbies); } } ``` ##### (b) 第三方库的支持 除了标准 API 外还有像 Apache Commons Lang 这样的外部组件提供了更灵活的选择——`HashCodeBuilder` 就是一例。它可以按照特定模式逐步累加各个属性的影响因子从而得出综合得分[^3]: ```java import org.apache.commons.lang3.builder.HashCodeBuilder; public class Employee { private final String firstName; private final String lastName; // Constructor & Getters omitted @Override public int hashCode(){ return new HashCodeBuilder(17,31). // two randomly chosen prime numbers append(this.firstName). append(this.lastName). toHashCode(); } } ``` 以上两种途径都能有效降低手动编码错误风险的同时增强可读性和维护便利度。 #### 5. 特殊情况处理 对于数组类型的成员变量需要注意单独对待因为简单拼接可能引发潜在问题;另外还要考虑 null 安全等因素以免运行期异常发生。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值