资讯专栏INFORMATION COLUMN

关于equals和hashCode方法的一些理解

ctriptech / 1042人阅读

摘要:而这次在一的一方实体里重写基类的和方法做去重,感觉用的代码量减少了,又能提高效率,所以我这里对这两个方法做些自己的理解。不相等的两个对象,不一定不相等。不相等,那么是一定不等的。文章若有错误之处,欢迎指出。

昨天写hibernate一对多查询的时候,用set集合来储存值,
我们都知道java中List集合是有序,可重复的,Set集合是无序,不可重复的。所以当时写这个查询的时候果断用Set来存值,但还是出现了值重复问题。
具体请看SF上提问:https://segmentfault.com/q/10...

我之前做的在for里对set有去重做法,但是有不足之处的。而这次在“一”的一方实体里重写Object基类的hashCode和equals方法做去重,感觉用的代码量减少了,又能提高效率,所以我这里对这两个方法做些自己的理解。

1、hashCode()和equals()是什么
hashCode和equals方法是在Object基类中,所以每个对象都可以重写这两个方法,
看看JDK中这两个方法源码

hashCode

/**
 * 查看hashCode源码是native修饰的, 说明这个方法是个原生函数,
 * 也就是说这个方法不是用java实现的,底层是用C/C++实现的
 * 返回哈希值
*/
 public native int hashCode();

equals

/*
用来比较两个引用所指向的对象内存地址是否一致
*/
 public boolean equals(Object obj) {
        return (this == obj);
    }

2、hashCode()和equals()关系是什么?
明白几个原则:
equals相等的两个对象,hashcode一定相等。
equals不相等的两个对象,hashcode不一定不相等。
hashcode不相等,那么equals是一定不等的。
hashcode相等,equals可能相等,也可能不等。
解释下第四个原则:
就好比hashcode像是一个词典目录里的按字母为索引查找字,查一个“Z”拼音开头的词,下面等查到“自己”,“自我”,“知道”等词,用equals就是判断这些词语当中是否有相等的词,“自己”和“知道”两个词不相等的,所以equals值不等,但它们同属于"Z"开头的词所以它们hashcode值相等。

3、为什么重写equals的同时也要重写hashCode呢?
这个问题不难解释,就像前面问题一样,hash算法是为了提高equals比较的效率而被发明出来的。这点在集合方面就能体现出来,就比如在List或Set集合里要比较是否有重复元素,当发现某个集合对象与另一个集合对象equals比较的结果相等时,则停止查找返回true值,反之,返回false值。但如果集合中有大量元素呢,假设一个集合A里有10万元素,而且另一个比较的对象B中还可能没有重复的值,则意味着其实不用比较我都知道两者不相同,但程序依然会对集合A里遍历10万元素然后和B进行逐一排查。。。又或者当我要加入第100001个数据我要验证前面元素有重复值,就要跟前面10万个元素一一比较,效率可想而知很低。

而哈希算法就是Java系统首先调用对象的hashCode()方法获得该对象的哈希码表,然后根据哈希码找到相应的存储区域,若哈希码相同在取得该存储区域内的每个元素与该对象进行equals方法比较,若不同也就没有继续比较的必要了,这对于数量较大的情况效率就提高了不少,重写hashcode方法,最主要就是保证操作的元素在同一个对象里且值都没有重复,若没有重写hashcode,可能会出现将对象引用不同,但元素完全相同的集合进行操作。

下面写一个例子

package demo;

public class override_HshCode_Equals {
    public int x;
    public int y;

    public override_HshCode_Equals(int x, int y) {
        this.x = x;
        this.y = y;
    }

    @Override
    public int hashCode() {
        //下面变量初始化值可以任意取
        final int prime = 31;
        int result = 1;
        result = prime * result + x;
        result = prime * result + y;
        return result;
    }

    /**
     * equals返回false就说明没有重复项可以添加
     * true是重复不能添加
     */
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;

        final override_HshCode_Equals heClass = (override_HshCode_Equals) obj;
        //这里就对实例化对象里的x,y进行比较
        if (x != heClass.x) {
            return false;
        }
        if (y != heClass.y) {
            return false;
        }
        return true;
    }
}

测试类

package demo;

import java.util.HashSet;

public class TestMain {
    public static void main(String[] args) {
        HashSet set = new HashSet();
        override_HshCode_Equals heClass1 = new override_HshCode_Equals(1, 1);
        override_HshCode_Equals heClass2 = new override_HshCode_Equals(5, 5);
        override_HshCode_Equals heClass3 = new override_HshCode_Equals(1, 1);
        set.add(heClass1);
        set.add(heClass2);
        set.add(heClass3);
        set.add(heClass1);
        System.out.println("set数量=" + set.size());
    }
}

结果如下

set数量=2

注:重写override_HshCode_Equals类的hashCode相当于自定义返回了一个“哈希码”,对比x,y值是否相等,先比较hashcode值,heClass1(3,3)==heClass3(3,3),所以它们的hashcode值相等,但是heClass2的x,y和heClass1,heClass3的x,y值不等,所以hashcode不等,equals一定不等,所以heClass2对象是可以add进去的。前面说了heClass1和heClass3的hashcode值相等,然后进入equals进行对比,发现两者的对象都是相同的,根据程序add循序来看,所以heClass1是可以add进去的,然后heClass3和后面add(heClass1)都为重复项,就不会添加

注释override_HshCode_Equals里的hashCode方法
结果如下

set数量=3

注:首先判断heClass1对象和heClass2对象的hashCode,此时Object中的hashCode方法返回的是对象本地内存地址的换算结果,不同的实例对象的hashCode是不相同的,同样因为heClass3和heClass1的hashCode也是不相等的,但是后面第四个添加中heClass1==heClass1的,所以最后set集合中只有heClass1,heClass2,heClass3这三个对象。

修改:override_HshCode_Equals heClass3 = new override_HshCode_Equals(1, 2);
结果如下

set数量=3

注:此时对比heClass1,heClass2,heClass3的x,y值都不相同,hashcode值不同,而第四个添加heClass1=heClass1,故添加不进去,set里有heClass1,heClass2,heClass3。

文章若有错误之处,欢迎指出。

参考网站:
http://www.cnblogs.com/ysch/p/4323889.html

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/70440.html

相关文章

  • HashMap 工作原理

    摘要:的工作原理是近年来常见的面试题。让我们再来看看这些问题设计哪些知识点的概念中解决碰撞的方法和的应用,以及它们在中的重要性不可变对象的好处多线程的条件竞争重新调整的大小总结的工作原理基于原理,我们通过和方法储存和获取对象。 HashMap 的工作原理是近年来常见的 Java 面试题。几乎每个 Java 程序员都知道 HashMap,都知道哪里要用 HashMap,知道Hashtable和...

    zhisheng 评论0 收藏0
  • 重新详尽理解HasMap

    摘要:根据的重新计算值。如果这两个的通过比较返回,新添加的将覆盖集合中原有的,但不会覆盖。如果这两个的通过比较返回,新添加的将与集合中原有形成链,而且新添加的位于链的头部具体说明继续看方法的说明。 关于hashCode hashCode的存在主要是用于查找的快捷性,如Hashtable,HashMap等,hashCode是用来在散列存储结构中确定对象的存储地址的. 1.hashcode是用来...

    maxmin 评论0 收藏0
  • Java知识体系之Java基础

    摘要:最近看到上面的一篇博客面试必备最常见的面试题全解析讲解了关于体系的一些模块以及面试中的一些常见问题虽然最近没有要去找工作的需求但是巩固一下这方面的知识还是很有必要的后面从作者提出的问题进行自我的提问与解答有问题欢迎大家指出基础部分和的区别我 最近看到CSDN上面的一篇博客 面试必备:《Java最常见的200+面试题全解析》, 讲解了关于Java体系的一些模块以及面试中的一些常见问题; ...

    zhou_you 评论0 收藏0
  • 关于Hashmap个人理解

    摘要:当容量超过容量负载因子时,进行扩容操作确定何时将冲突的链表转换成红黑树用来确何时将红黑树转换成链表当链表转换成红黑树时,需要判断数组容量。桶排序核心思想是根据数据规模划分,个相同大小的区间每个区间为一个桶,桶可理解为容器。 刚刚看到QQ群有人吹Hashmap,一想我啥都不懂,就赶快补了一波。下面分享一下我对Hashmap的理解,主要用于个人备忘。如果有不对,请批评。想要解锁更多新姿势?...

    Yujiaao 评论0 收藏0
  • Java编程中那些再熟悉不过知识点(持续更新)

    摘要:语言通过字节码的方式,在一定程度上解决了传统解释型语言执行效率低的问题,同时又保留了解释型语言可移植的特点。有针对不同系统的特定实现,,,目的是使用相同的字节码,它们都会给出相同的结果。项目主要基于捐赠的源代码。 本文来自于我的慕课网手记:Java编程中那些再熟悉不过的知识点,转载请保留链接 ;) 1. 面向对象和面向过程的区别 面向过程 优点: 性能比面向对象高。因为类调用时需要实例...

    taowen 评论0 收藏0

发表评论

0条评论

ctriptech

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<