HashCode

HashCode

前言

Hash是什么?

哈希函数
把任意长度的输入通过散列算法变换成固定长度的输出,该输出就是散列值,是一种压缩映射。

hash是一个函数,该函数中的实现就是一种算法,就是通过一系列的算法来得到一个hash值。hash表,通过hash算法得到的hash值存在hash表中,也就是说,hash表就是所有的hash值组成的,hash函数可以有很多种,只要能实现得到的每一个值不重复就可以。

Hash函数特性
h(k1)≠h(k2)则k1≠k2,即散列值不相同,则输入值即预映射不同
如果k1≠k2,h(k1)=h(k2) 则发生碰撞;
如果h(k1)=h(k2),k1不一定等于k2;

Hash的使用场景
什么时候使用hash函数?
如果从互联网下载一个文件,文件的下载过程中会经过很多网络服务器、路由器的中转,如何保证这个文件就是我们所需要的呢?不可以通过文件名,文件大小,文件类型这些容易被伪装的信息来判断,因为在传输的过程中这些信息很容易被修改和伪造。此时可以用hash算法来进行加密。通过hash算法对文件计算得到一个值,在本地在运用hash算法将这个值解析出来,如果文件被修改过,得到的值会不一样从而对文件进行加密保护。

HashCode

每个对象都可以计算hashcode,首先一个对象肯定有物理地址,将对象的物理地址转换成一个整数,然后该整数通过hash函数的算法就得到了hashcode,hashcode就是在hash表中对应的位置。

物理地址指对象存放在内存中的地址hashcode代表对象的地址在hash表中的位置

例:有一个hash表,表中有 hashcode为1、hashcode为2…hashcode为5这样5个位置,有一个对象A,假设A的物理地址转化为整数是17,通过特定的hash函数算出来的hashcode值为2(假设用物理地址%5来计算hashcode),则对象A应该在hash表中的2的位置。如果有一个对象B,算出来的hashcode值为3,则B应该在hashcode表中3的位置。如果有一个对象C,他计算出来的hashcode也等于2,则证明C和A的物理地址是一样的(假设hash函数正确,既不同的x值算出来的h(x)不同),则对象C和对象A应该是相等的。

HashCode关键点

1、HashCode的存在主要是为了查找的快捷性,hashcode是用来在散列存储结构中确定对象的存储地址的,通过hash函数可以快速的确定一个对象的物理地址。

2、如果两个对象equals相等,那么这两个对象的hashcode一定也相同,既equals相等,则物理地址相同,则计算出来的hashcode也一定相同。

3、如果对象的equals方法被重写,那么对象的HashCode方法也尽量重写,

4、如果两个对象的HashCode相同,不代表两个对象就相同,只能说明这两个对象在散列存储结构中,存放于同一个位置

判断两个对象相等

常用的.equals()去判断两个对象是否相等是需要重写equals方法的,重写equals方法时应该也尽量重写hashcode()方法。

例子:定义一个用户类,包含属性ID、name和age

public class Users {

    int id;
    String name;
    int age;

    public Users() {

    }

    public Users(int id, String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;

    }
}

在主函数中创建两个对象user1和user2,直接调用java自带的.equals()方法去比较:

public class Test {
    public static void main(String[] args) {
        Users user1=new Users(3,"John",5);
        Users user2=new Users(3,"John",5);
        if(user1.equals(user2)){
            System.out.println("相同");
        }else{
            System.out.println("不相同");
        }
    }
}

得到的结果为不相同,这是因为此时没有重写equals方法,用的是java本身的方法,可以看到它比较的是地址,因为两个对象都是new出来的所以地址是不一样的。
java中自带的equals方法:

public boolean equals(Object obj) {
        return (this == obj);
    }

这样是没有错误的,但是如果我们在实际运用中想让地址不同但是id,name,age都相同的两个对象相等怎么办,这时就需要重写equals方法,在Users类中重写equals方法:

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

可以看到在重写的equals方法中,首先用==比较的是两个对象的物理地址,如果物理地址相同则两个对象一定相同。然后判断输入的对象是不是为空或者两个对象的类型不一样,如果不一样直接返回false。然后去比较两个对象上的属性是不是一样,如果属性都一样就返回相同。
此时在运行main函数可以看到结果为相同。因为重写了equals方法,虽然两个对象的物理地址不同但是是根据实际需求将id,name,age相同的两个对象判断为相等。

同理,对hashcode也是一样的,如果不重写hashcode,则此时的user1和user2用hashcode判断时还是会得到不相同的结果。此时就需要重写hashcode方法:

@Override
    public int hashCode() {
        return Objects.hash(id, name, age);
    }

此时使用对象的所有属性id,name和age去计算hashcode,得到的结果一定是一样的,则会判断user1和user2相同。

为什么要重写hashcode:
前面已经讲过,如果判定两个对象equals,则他们的hashcode也一定要相同,这样就可以方便的进行存储和提升查找效率,比如user1和user2属性都一样,则他们判定为equals,此时可以只用一个地址去存储这个user对象,调用的时候得到的属性是一样的,这样就必须要求他们得到的hashcode值一样。如果不重写hashcode方法,运用java自带的方式得到的结果是不一样的,所以要重写hashcode方式使不同地址的但属性一样的两个对象hashcode也相等,他们在hash表中的位置一样。

不重写hashcode属性相同地址不同的两个对象方法得到的hashcode值:
在这里插入图片描述
重写hashcode方法以后属性相同地址不同的两个对象得到的结果:
在这里插入图片描述
可以看到两个user对象的hashcode值是一样的,这样就可以在hash表中放在同一位置,需要这个属性的user时就可以快速的通过hashcode找到地址并调用。

注意如果两个对象的hashcode相同不代表他们是equals的,不同的对象可能会生成相同的hashcode值,因为这只是说他们在hash表中的位置是相同的,要通过equals去判断是否相等。。虽然不能根据hashcode值判断两个对象是否相等,但是可以直接根据hashcode值判断两个对象不等,如果两个对象的hashcode值不等,则必定是两个不同的对象。如果要判断两个对象是否真正相等,必须通过equals方法。

也就是说对于两个对象,如果调用equals方法得到的结果为true,则两个对象的hashcode值必定相等;
如果equals方法得到的结果为false,则两个对象的hashcode值不一定不同;
如果两个对象的hashcode值不等,则equals方法得到的结果必定为false;
如果两个对象的hashcode值相等,则equals方法得到的结果未知。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值