HashMap中重写hashCode和equals方法

时间:2021-11-27 16:08:30
HashMap是一个非常有用的工具,我们可以放基本变量或者自己定义的对象来进行key-->value的查找

不过这里有个问题,请看举例

我们先创建一个自己的类,作为hashmap的key

class key
{
    int i ;
    public key(int i)
    {
    this.i = i;
    }
}


然后我们再定义一个类,作为hashmap的value

class value
{
    int j ;
    public value(int j)
    {
    this.j = j;
    }
    
    public String toString()
    {
    return ""+j;
    }
}


最后我们测试

public class Test
{
    public static void main(String[] args)
    {
    HashMap hm = new HashMap();
    
    key k = new key(1);   //******(1)
    value v = new value(2);
    
     hm.put(k, v);
    if(hm.containsKey(k)) //*********(2)
     System.out.println(hm.get(k)); //*********(3)
    else
     System.out.println("dont have such a key");
   
    }
}


注意,我这里的hashmap中的key是自己new出一个对象,然后把对象的引用作为key的,这里突出了hashmap的查找原理,hashmap是通过key的hashcode来找到hashmap中的key,这里我在hashmap的key中是放一个对象的应用,我去拿key的时候也是通过这个引用,所以(1)处的key 与(2)、(3)处的key是完全一样的,所以这段程序没有任何问题,顺利运行。

现在我把测试类改一下

public class Test
{
    public static void main(String[] args)
    {
    HashMap hm = new HashMap();
    
     hm.put(new key(1),new value(2));


    if(hm.containsKey(new key(1)))
     System.out.println(hm.get(new key(1)));
    else
     System.out.println("dont have such a key");
    }
}


注意区别,我这里hashmap中key放的不是引用,而是new出来的对象,然后我去get或者containsKey的时候也通过new一个key去拿,虽然我们初始化内容完全相同,都是放 int 1 进去,也就是说对象内容完全相同,但最后结果确实输出" dont have such a key"。

找原因,为什么内容相同,但找不到这个key呢,前面说了hashmap是通过hashcode来找key的位置,这是关键,你每次new 一个新对象出来hashcode肯定不一样,所以你拿不到你要的key。

解决方法,重写你编写的key类的hashcode方法。


class key
{
    int i ;
    public key(int i)
    {
    this.i = i;
    }
     @Override
    public boolean equals(Object obj)
    {
    if(obj instanceof key)
    {
     if(((key)obj).i == i)
        return true;
    }
    return false;
    }
     @Override
    public int hashCode()
    {
    return i;
    }
}


我们先不要看equals的重写,这里我们重写了hashcode这个方法,让它返回一个我们初始化进去的i,这样你每次new一个对象,因为是通过hashcode找key,而你的hashcode有只是值i,所以只要i相等,你就可以找到你的key的 地址 ,注意,只是找到你要的key的地址,但key是不是同一个key还不一定。

然后我们开始比较我们传来的寻找value的key和hashmap中的key是不是同一个key,如果是那就找到了value。

在未重写equals方法我们是继承了object的equals方法,那里的 equals是比较两个对象的内存地址,显然我们new了2个对象内存地址肯定不一样,所以我们还要重写equals这个方法,让重写后的equals方法来比较我们对象里特有的东西。

重写equals方法一般按照如下步骤:
1.先判断这两个比较的对象是不是同个类型,如果类型都不相同,肯定不相同;
2.如果类型相同,我们先要把Object向下转型到我们的类类型,然后比较自己类特有的变量,这里我只是比较了类里i值是否相同,如果相同,则表明两个对象是相同的(只是作为hashmap的key来说是相同的),这样就可拿到hashmap的value了。

总结
hashmap中value的查找是通过 key 的 hashcode 来查找,所以对自己的对象必须重写 hashcode 通过 hashcode 找到对对象后会用 equals 比较你传入的对象和 hashmap 中的 key 对象是否相同,所以要重写 equals.

//*******************

现在我们开始造假

因为前面说了hashmap是通过hashcode来找到key的位置,然后通过equals来比较key内容是否相同

那我们就可以做一个其它的类,但hashcode和equals和前面的key这个类完全相同

class key1
{
    int i ;
    public key1(int i)
    {
    this.i = i;
    }
    
     @Override
    public boolean equals(Object obj)
    {
    if(obj instanceof key)
    {
     if(((key)obj).i == i)
        return true;
    }
    return false;
    }
     @Override
    public int hashCode()
    {
    return i;
    }
}


这样的话我在测试类Test中加上一句

public class Test
{
    public static void main(String[] args)
    {
    HashMap hm = new HashMap();

     hm.put(new key(1),new value(2));
    hm.put(new key1(1), new value(22222222)); //***这句是加的


    
    if(hm.containsKey(new key(1)))
     System.out.println(hm.get(new key(1)));
    else
     System.out.println("dont have such a key");
    }
}


现在问题就来了,因为key1和key的hashcode定义都完全一样,就是说 new key(1) 和 new key1(1) 的hushcode完全一样,这样一来先定义的 new key(1) 就被后定义的 new key1(1) 覆盖了, 前面说了hashmap只是根据hashcode来找key位置,只要hushcode 一样就可以找到 key 的位置,所以我们是可以通过 new key(1) 来找到 new key1(1) 这个key的位置的,而且由于 key 类和 key1 类里的equals方法也一样,我们就可以用 new key(1)来假冒new key1(1) ,来拿到new key1(1) 对应的value值。

当然如果你想拿new value(2)这个value是肯定拿不到了,呵呵。