一道关于hashSet与hashMap底层实现的面试题

题目

public class TestPerson {
    public static void main(String[] args) {
        HashSet<Person> set = new HashSet<>();
        Person p1 = new Person(1001, "AAA");
        Person p2 = new Person(1002, "BBB");

        set.add(p1);
        set.add(p2);
        p1.name = "CCC";
        set.remove(p1);
        System.out.println(set);

        set.add(new Person(1001,"CC"));
        System.out.println(set);

        set.add(new Person(1001,"AAA"));
        System.out.println(set);
    }
}

其中Person类重写了hashCode、equals、和toString方法

public class Person {
    int age;
    String name;

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

    @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(age, name);
    }

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}

问输出结果是多少?


分析

答题前我们首先要知道:
JDK1.8后,HashSet和HashMap存储结构都是哈希表(由数组+链表+红黑树实现)。

HashSet和HashMap存储过程:
1.根据key的hash值计算位置,如果这个位置没有元素,则直接添加。
2.如果这个位置有元素,再比较hash值,如果hash值不同,则形成链表。
3.如果hash值相同,再比较equals方法,如果equals方法为false,则形成链表,如果为true,则认为是重复元素,不再添加。
位置相同,hash值相同,equals为true同时成立才认为是重复元素。

HashSet和HashMap删除过程:
同理要位置相同,hash值相同,equals为true同时成立才认为是重复元素,才能删除。

回到题目
set.add(p1)、set.add(p2): set首先添加p1(1001,“AAA”)、p2(1002,“BBB”)对象后,将p1对象的name值改变了(1001,“CCC”),此时虽然set中p1的属性值为(1001,“CCC”),但其数组位置是按照(1001,“AAA”)计算的。
set.remove(p1): 此时位置是按照更改后的(1000,“CCC”)计算的,与set中存储的p1的位置不同,故认为set中没有与之重复的元素,不删除。
set.add(new Person(1001,“CC”)): 理由同上,此时按照更改后的属性计算的位置与原本计算的位置不同,故认为set中没有与之重复的元素,于是将其添加进数组。
set.add(new Person(1001,“AAA”)): 属性与p1原属性相同,按照此属性计算的位置与p1在数组中存储的位置相同,于是再比较hash值,hash值不同(重写了hashCode函数,属性相同hash相同,属性不同hash不同。当然,不重写hashCode函数两者hash值也不同)。故认为两者不是重复元素,将新对象添加再p1后形成链表。
综上,这道题最后的答案是:在这里插入图片描述

hashCode()方法和equal()方法的作用其实一样,在Java里都是用来对比两个对象是否相等一致,那么equal()既然已经能实现对比的功能了,为什么还要hashCode()呢?

答:因为重写的equal()里一般比较的比较全面比较复杂,这样效率就比较低,而利用hashCode()进行对比,则只要生成一个hash值进行比较就可以了,效率很高。

hashCode()既然效率这么高为什么还要equal()呢?

答:因为hashCode()并不是完全可靠,有时候不同的对象他们生成的hashcode也会一样(生成hash值的公式存在的问题),所以hashCode()只能说是大部分时候可靠,并不是绝对可靠。

参考文章:https://blog.csdn.net/weixin_30229705/article/details/112441923

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值