HashMap get(Key) 返回值的坑

HashMap 使用Object 对象作为Key 时, 如果Key 对应的类,重写了 hashCode() 和 equals 方法,

则可能会导致使用 同一个类不同实例对象, 去从map 中获取 值时,得到的是同一个值。

例子如下:

1. 先自定义一个类

仅有两个成员变量,都是String 类型。 并且重写其hashCode() 和 equals 方法。

其中

(1). 根据成员变量的值进行hashCode 计算,

(2). equals 方法 是比较两个对象的成员变量是否一样,一样则返回true

import java.util.Objects;

public class TargetItem {
    String mId;
    String mName;

    public TargetItem(String id, String name) {
        this.mId = id;
        this.mName = name;
    }

    @Override
    public String toString() {
        return "TargetItem{" +
                "mId='" + mId + '\'' +
                ", mName='" + mName + '\'' +
                '}';
    }

    //2. hashCode 一样的情况下, 才会调用equals 比较,例如可以根据成员变量的值比较
    @Override
    public boolean equals(Object other) {
        System.out.println("正在调用"+ mName+ " 的equals方法 ");
        boolean ret;
        //ret = (this == other); // 引用地址的比较,两个实例对象,必然返回false

        if (this == other) return true;
        if (other == null || getClass() != other.getClass()) return false;
        TargetItem that = (TargetItem) other;
        //ret = Objects.equals(mId, that.mId) && Objects.equals(mName, that.mName);
        // 成员变量的值的比较,即使两个实例对象地址不一样,内容一样则返回true
        ret = mId.equals(that.mId) && mName.equals(that.mName);
        System.out.println("equals 返回结果=" + ret);

        return ret;
    }

    // 1. 先要确定hashCode 一样才会调用 equals
    @Override
    public int hashCode() {
        return Objects.hash(mId, mName);
    }
}

2. 测试代码:

import java.util.HashMap;

public class MainTest {

    public static void main(String args[]) {

        System.out.println("========1. 创建实例对象==================");

        TargetItem tom1 = new TargetItem("1", "Tom");
        System.out.println("tom1=" + tom1 + ", hashcode=" + tom1.hashCode());
        TargetItem tom2 = new TargetItem("1", "Tom");
        System.out.println("tom2=" + tom2 + ", hashcode=" + tom2.hashCode());
        System.out.println("tom1==tom2: " + (tom1 == tom2));

        System.out.println();
        System.out.println("========2.仅将 tom1 填入 HashMap==================");
        HashMap hashMap = new HashMap();
        hashMap.put(tom1, "我是Tom");

        System.out.println();
        System.out.println("========3.根据tom1 作为key值get========");
        System.out.println("value: " + hashMap.get(tom1));

        System.out.println();
        System.out.println("========4.根据tom2 作为key值get ========");
        System.out.println("value: "+hashMap.get(tom2));
    }
}

输出结果:

> Task :javatest:MainTest.main()
========1. 创建实例对象==================
tom1=TargetItem{mId='1', mName='Tom'}, hashcode=86754
tom2=TargetItem{mId='1', mName='Tom'}, hashcode=86754
tom1==tom2: false

========2.仅将 tom1 填入 HashMap==================

========3.根据tom1 作为key值get========
value: 我是Tom

========4.根据tom2 作为key值get ========
正在调用Tom 的equals方法 
equals 返回结果=true
value: 我是Tom

可以看到,tom1 / tom2 的地址值时不同的, 因此 (tom1== tom2) 返回false,

而根据tom2 去get 时, 返回的值是和使用tom1时 一样的值,因为tom1/tom2的hashCode()一样,并且它们类的equals 返回true.

查看HashMap的字节码文件,可以看出, HashMap 在进行get操作时,是会先根据传入的对象的hashCode() 值进行hash计算

public class HashMap<K, V> extends AbstractMap<K, V> implements Map<K, V>, Cloneable, Serializable {

    public V get(Object var1) {
        HashMap.Node var2;
        return (var2 = this.getNode(hash(var1), var1)) == null ? null : var2.value;
    }

    static final int hash(Object var0) {
        int var1;
        return var0 == null ? 0 : (var1 = var0.hashCode()) ^ var1 >>> 16;
    }

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值