Map使用对象作key

Map介绍:

Map是一个集合,一种依照键(key)存储元素的容器,键(key)很像下标,在List中下标是整数。在Map中键(key)可以是任意类型的对象。Map中不能有重复的键(Key),每个键(key)都有一个对应的值(value);

Map的key和value都是泛型的,所以Map的key和value可以任意类型的

(泛型讲解:https://wenku.baidu.com/view/511465055a0102020740be1e650e52ea5518ceae.html

hashCode方法详解(https://wenku.baidu.com/view/f0e3903e13a6f524ccbff121dd36a32d7375c761.html

使用对象做Map的key会出现那些问题:

不重写HashCode方法和equals方法时:

内容相等的对象创建多次,分别调用hashCode方法获取的哈希值都是不相等的,所以HashMap中会出现相同的key对象存在;解决这个的办法对象重写HashCode方法和equals方法,使用指定的哈希算法和equals方法这样可以避免上述情况;

重写HashCode方法和equals方法出现时:

当修改已经存放在HashMap中的对象时,HashMap中key也会同步修改,但是这个key所在的哈希值还是之前的哈希值所在的位置,这样会出现,使用修改前的key查value,查到所在的位置但是调用equals方法两个key值不相等结果查不到值,使用新的key去找,会通过新的key对象的哈希值去找,两个哈希值不相等,也查不到之前的value值了,这个值永远也查不到了;

实验key对象的案例:

/**
 * 创建用户对象
 */
class User implements Serializable {

    /**
     * 姓名
     */
    public String name;
    /**
     * 身份证号
     */
    public String idCard;
    /**
     *班级
     */
    public String clazz;

    public String getName() {
        return name;
    }

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

    public String getIdCard() {
        return idCard;
    }

    public void setIdCard(String idCard) {
        this.idCard = idCard;
    }

    public String getClazz() {
        return clazz;
    }

    public void setClazz(String clazz) {
        this.clazz = clazz;
    }

    public static void main(String[] args) {
        //创建用户对象做key的HashMap集合
        HashMap<User, String> map = new HashMap<>();
        /**
         * 创建小明用户对象
         * 存放到map中
         */
        User xiaoMing = new User();
        xiaoMing.setName("小明");
        xiaoMing.setIdCard("4243124");
        xiaoMing.setClazz("二班小明");
        map.put(xiaoMing,"xiaoMing");
        System.out.println("xiaoMing的哈希值:"+xiaoMing.hashCode());

        /**
         * 在重新新建小明对象
         * 存放到map中
         */
        User xiaoMing2 = new User();
        xiaoMing2.setName("小明");
        xiaoMing2.setIdCard("4243124");
        xiaoMing2.setClazz("二班小明");
        map.put(xiaoMing2,"xiaoMing2");
        System.out.println("xiaoMing2的哈希值:"+xiaoMing2.hashCode());
        for (User user : map.keySet()) {
            System.out.println(map.get(user));
        }

    }

}

运行结果(控制台输出了两个小明对象):
在这里插入图片描述

原因HashMap是通过key的哈希值去放的元素的

HashMap putget方法源码解析文章(https://wenku.baidu.com/view/b9865541f6335a8102d276a20029bd64783e6281.html )

在这里插入图片描述

解决上述问题方式:

用户实体类中重写equals方法和hashCode方法或者使用Lombok中的@EqualsAndHashCode注解;

/**
 * 创建用户对象
 */
//@EqualsAndHashCode
class User implements Serializable {

    /**
     * 姓名
     */
    public String name;
    /**
     * 身份证号
     */
    public String idCard;
    /**
     *班级
     */
    public String clazz;

    public String getName() {
        return name;
    }

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

    public String getIdCard() {
        return idCard;
    }

    public void setIdCard(String idCard) {
        this.idCard = idCard;
    }

    public String getClazz() {
        return clazz;
    }

    public void setClazz(String clazz) {
        this.clazz = clazz;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return name.equals(user.name) && idCard.equals(user.idCard) && clazz.equals(user.clazz);
    }

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

    /**
     * main方法测试
     * @param args
     */
    public static void main(String[] args) {
        //创建用户对象做key的HashMap集合
        HashMap<User, String> map = new HashMap<>();
        /**
         * 创建小明用户对象
         * 存放到map中
         */
        User xiaoMing = new User();
        xiaoMing.setName("小明");
        xiaoMing.setIdCard("4243124");
        xiaoMing.setClazz("二班小明");
        map.put(xiaoMing,"xiaoMing");
        System.out.println("xiaoMing的哈希值:"+xiaoMing.hashCode());

        /**
         * 在重新新建小明对象
         * 存放到map中
         */
        User xiaoMing2 = new User();
        xiaoMing2.setName("小明");
        xiaoMing2.setIdCard("4243124");
        xiaoMing2.setClazz("二班小明");
        map.put(xiaoMing2,"xiaoMing2");
        System.out.println("xiaoMing2的哈希值:"+xiaoMing2.hashCode());
        for (User user : map.keySet()) {
            System.out.println(map.get(user));
        }

    }

}

重写之后的结果(map中只有一个元素了):
在这里插入图片描述

重写之后有出现新的问题:

再次修改map中key的对象之后将永久获取不到之前的值了;

如果再次保存的话也不会覆盖之前的元素只会新增一个元素如下实验;

/**
 * 创建用户对象
 */
class User implements Serializable {

    /**
     * 姓名
     */
    public String name;
    /**
     * 身份证号
     */
    public String idCard;
    /**
     *班级
     */
    public String clazz;

    public String getName() {
        return name;
    }

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

    public String getIdCard() {
        return idCard;
    }

    public void setIdCard(String idCard) {
        this.idCard = idCard;
    }

    public String getClazz() {
        return clazz;
    }

    public void setClazz(String clazz) {
        this.clazz = clazz;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return name.equals(user.name) && idCard.equals(user.idCard) && clazz.equals(user.clazz);
    }

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

    /**
     * main方法测试
     * @param args
     */
    public static void main(String[] args) {
        //创建用户对象做key的HashMap集合
        HashMap<User, String> map = new HashMap<>();
        /**
         * 创建小明用户对象
         * 存放到map中
         */
        User xiaoMing = new User();
        xiaoMing.setName("小明");
        xiaoMing.setIdCard("4243124");
        xiaoMing.setClazz("二班小明");
        map.put(xiaoMing,"xiaoMing");
        System.out.println("xiaoMing的哈希值:"+xiaoMing.hashCode());
        xiaoMing.setClazz("三班小明");
        map.put(xiaoMing,"三班小明");
        System.out.println("三班xiaoMing的哈希值:"+xiaoMing.hashCode());
        map.get(xiaoMing);

        /**
         * 在重新新建小明对象
         * 存放到map中
         */
        User xiaoMing2 = new User();
        xiaoMing2.setName("小明");
        xiaoMing2.setIdCard("4243124");
        xiaoMing2.setClazz("二班小明");
        map.put(xiaoMing2,"xiaoMing2");
        System.out.println("xiaoMing2的哈希值:"+xiaoMing2.hashCode());
        for (User user : map.keySet()) {
            System.out.println(map.get(user));
        }

    }

}

运行数据时
在这里插入图片描述

结果如下:

在这里插入图片描述

原因是因为修改了key对象之后同步修改了之前的key但是map存储时使用key是之前的key存放的元素 所以就找不到之前的元素了

而且使用keySet循环查也找不到之前的数据了 就是因为使用新key的哈希值和之前的不一样造成的

& 号详细讲解:https://blog.csdn.net/IT_dog/article/details/123212486

在这里插入图片描述

结语

谢谢观看,如有疑问欢迎留言,上面的验证和解析可能有错误之处,欢迎留言指导。

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐