哈希码 以及hashCode()是使用

Java中,

  • 哈希码(Hash Code)是通过hashCode()方法来获取的。

  • 每个对象都可以调用hashCode()方法来获取其哈希码,该哈希码是一个32位整数。

  • 哈希码的作用是,帮助在哈希表等数据结构中快速查找对象。


在Java中,
hashCode()方法是定义在Object类中的,因此所有的Java对象都具有hashCode()方法。
默认情况下,hashCode()方法会返回对象的内存地址经过哈希算法计算得到的值,但是可以根据需要在自定义类中重写hashCode()方法以提供更合适的哈希码计算逻辑。

在重写hashCode()方法时,通常需要遵循以下规则:

  1. 如果两个对象根据equals()方法是相等的,则它们的哈希码必须相等。
  2. 如果两个对象根据equals()方法是不相等的,它们的哈希码可以相等也可以不相等,但是为了提高哈希表的性能,最好让不相等的对象的哈希码尽可能不相等。

在实际编程中,当自定义类需要作为哈希表的键或存储在哈希集合中时,通常需要重写hashCode()方法和equals()方法,以确保对象在哈希表中的正确存储和检索。


需要注意的是,当重写equals方法时,通常也需要重写hashCode方法,以确保满足哈希码的唯一性和一致性要求。如果不重写hashCode方法,而只重写了equals方法,可能会导致在哈希表等数据结构中出现错误的行为。




Java中,
除了基本数据类型(byte, short, int, long, float, double, char, boolean)之外,所有的对象类型(包括数组和枚举)都继承自java.lang.Object类。Object类定义了一个hashCode()方法,因此这些对象类型都可以调用hashCode()方法来获取哈希码。

这包括:

  • 字符串:String类也重写了hashCode()方法,以返回一个基于字符串内容的哈希码。

  • 引用类型:任何类的实例都是对象,都可以调用hashCode()。如果类没有重写hashCode()方法,那么将使用Object类中的默认实现,该实现通常基于对象的内存地址,但这不是必须的,具体实现可能因JVM而异。

  • 数组:数组也是对象,在Java中数组隐式地继承自Object类。因此,你可以对数组调用hashCode()方法。但是,数组类的hashCode()方法并没有被重写,所以它使用的是Object类的默认实现,这通常不是很有用。对于数组,你通常应该使用Arrays.hashCode(array)来获取一个基于数组内容的哈希码。

  • 接口:虽然接口不能直接实例化,但是接口的任何实现类都是对象,可以调用hashCode()。接口的实例实际上是实现了该接口的类的对象。

  • 枚举类型:枚举常量也是对象,可以调用hashCode()。枚举类型隐式地继承自java.lang.Enum类,而Enum类继承自Object类。

  • 包装类:基本数据类型的包装类(如Integer, Double等)都是对象,它们重写了hashCode()方法以基于它们包装的基本值返回一个哈希码。

当你重写类的hashCode()方法时,你应该确保相等的对象(即equals()方法返回true的对象)具有相同的哈希码,以维护哈希表数据结构的正确性。如果不相等的对象具有相同的哈希码,就会发生哈希冲突,这虽然不会导致错误,但可能会降低哈希表的性能。




这里全是 基本数据类型的变量
public class Birthday {
    private int year;
    private int month;
    private int day;

    public Birthday() {
    }

    public Birthday(int year, int month, int day) {
        this.year = year;
        this.month = month;
        this.day = day;
    }
	
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = result * prime + year;
        result = result * prime + month;
        result = result * prime + day;
        return result;
    }

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

        Birthday birthday = (Birthday) obj;
        return year == birthday.year
                && month == birthday.month
                && day == birthday.day;
    }
}
---------- 对上面代码的 这个方法 做出解释:----------

public int hashCode() {
  final int prime = 31;
  int result = 1;
  result = result * prime + year;
  result = result * prime + month;
  result = result * prime + day;
  return result;
}

这里,最后只返回最终的result,但是为什么这里要把每个字段都进行一下处理呢?

这个 hashCode() 方法的目的,是为了生成一个基于对象内部状态的唯一标识符,即哈希码。
在Java中,hashCode() 方法通常与 equals() 方法一起使用,以确保当两个对象相等(通过 equals() 方法判断)时,它们的哈希码(通过 hashCode() 方法生成)也相等。

在提供的代码中,
hashCode() 方法使用了三个字段(year、month、day)来计算最终的哈希码,
每个字段都通过乘以一个质数(prime)然后加上字段值的方式进行处理。
这样做有几个原因:
	"减少哈希冲突":通过乘以一个质数并加上字段值,可以增加不同字段组合生成的哈希码之间的差异,从而减少哈希冲突的可能性。
				   哈希冲突是指不同的对象具有相同的哈希码,这可能导致性能下降,因为当使用哈希表等数据结构时,需要额外的处理来解决冲突。
	
	"考虑字段的顺序":由于每个字段都单独处理,字段的顺序会影响最终的哈希码。这有时是必要的,例如,当对象的相等性取决于字段的顺序时。
	
	"散列效果":乘以质数(如31)的操作具有良好的散列效果,可以将输入值均匀地分布到整个整数范围内,从而生成更好的哈希码。

最后,返回的是最后一个计算得到的 result,它综合了所有字段的影响,从而生成一个基于对象所有字段的哈希码,
这个哈希码应该尽可能地唯一,以支持在哈希表等数据结构中的高效查找和比较操作。

再看看这里

import java.util.Objects;
public class Employee {
    private Integer id;
    private String name;
    private Birthday birthday;

    public Employee() {
    }
    
    public Employee(Integer id, String name, Birthday birthday) {
        this.id = id;
        this.name = name;
        this.birthday = birthday;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = result * prime + ((id == null) ? 0 : id.hashCode());
        result = result * prime + ((name == null) ? 0 : name.hashCode());
        result = result * prime + ((birthday == null) ? 0 : birthday.hashCode());
        return result;
    }

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

        Employee employee = (Employee) obj;
        return Objects.equals(employee.id, id)
                && Objects.equals(employee.name, name)
                && Objects.equals(employee.birthday, birthday);
    }

    @Override
    public String toString() {
        return "Employee{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", birthday=" + birthday +
                '}';
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public Birthday getBirthday() {
        return birthday;
    }

    public void setBirthday(Birthday birthday) {
        this.birthday = birthday;
    }
}

  • 8
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值