equals null报错吗_轻轻松松教你搞定Java中的==和equals

2235c687c7df2a06ba42df8452e9ed45.png

前言

相信很多读者关于==equals懂了又懵,懵了又懂,如此循环,事实上可能是因为看到的博客文章之类的太多了,长篇大论,加上一段时间的洗礼之后就迷路了。本篇文章再一次理清楚。当然如果觉得本文太啰嗦的话,当然我也考虑到了,因为我也不喜欢长篇大论啰里啰嗦比比叨叨胡搅蛮缠的文章,毕竟大家入门java 的时候就知道个大概了,因此记住一句话就好了:equals本身和 == 没有区别,对于基本数据都是比较值,对于引用类型,则比较的是所指向的对象的地址!其他类在继承Object类之后对equals方法重写,所以表现的是比较里面的内容!具体比较的则要看自己是怎么重写的。

好了,如果有兴趣的就看下文,当然不感兴趣的大佬可以点个赞直接走了,不用看了,会了还看个*啊,楼主你个憨憨(皮一下很开心)

1、原生的equals()方法本身与 “ == ”没有任何区别!

从java语言本质上来讲,"=="属于JAVA语言的运算符,而equals则是根类Object的一个方法。

关于Object类的equals()方法,我们可以看看其源码

/*     * @param   obj   the reference object with which to compare.     * @return  {@code true} if this object is the same as the obj     *          argument; {@code false} otherwise.     * @see     #hashCode()     * @see     java.util.HashMap     */public boolean equals(Object obj) {    return (this == obj);}

是的,equals底层其实就是“ == ”,也就是说,原生的equals()方法本身与 “ == ”没有任何区别!唯一的区别则是基本类型没有继承Object类,所以基本类型没有equals()方法,也就是说基本类型只能使用“ == ”判断值是否相等。

既然原生的equals()方法本身与 “ == ”没有任何区别,那么我们对运算符 “ == ”的使用有所了解即可!

运算符 “ == ”其具体作用是用来比较值是否相等,这里分两中情况:

  • 1、基本数据类型的变量,则直接比较其存储的 “值”是否相等;
  • 2、引用类型的变量,则比较的是所指向的对象的地址是否相等;

到这里我们可以初步确认原生的equals()方法本身与 “ == ”没有任何区别!作用正是如上。

下面是我们的一个专栏 《Java 进阶集中营》,有兴趣的朋友们可以关注一下!
JAVA 进阶集中营​zhuanlan.zhihu.com
5a88377f00aa00d3bd9a9c2d8ed0c355.png

2、equals()方法的重写

但是重点来了,因为对于equals()方法我一直在强调原生二字。是的,让很多初学者疑惑的点就在这里:equals()方法的重写!

在JDK中,诸如StringDate等类对equals方法进行了重写,以String为例,这里感兴趣的读者可以一起看看String类中重写的equals()方法,当然跳过也问题不大

/**     * Compares this string to the specified object.  The result is {@code     * true} if and only if the argument is not {@code null} and is a {@code     * String} object that represents the same sequence of characters as this     * object.     *     * @param  anObject     *         The object to compare this {@code String} against     *     * @return  {@code true} if the given object represents a {@code String}     *          equivalent to this string, {@code false} otherwise     *     * @see  #compareTo(String)     * @see  #equalsIgnoreCase(String)     */    public boolean equals(Object anObject) {        if (this == anObject) {            return true;        }        if (anObject instanceof String) {            String anotherString = (String) anObject;            int n = value.length;            if (n == anotherString.value.length) {                char v1[] = value;                char v2[] = anotherString.value;                int i = 0;                while (n-- != 0) {                    if (v1[i] != v2[i])                            return false;                    i++;                }                return true;            }        }        return false;    }

从源码中可以看出,首先该方法判断比较的是所指向的对象地址是否相等,如果相同直接返回true,如果不相同进行下一个if判断,第二个if判断大致意思则是比较其存储的 “值”是否相等,也就是比较内容值!相同就返回true,比如两个new String对象“AAA”“AAA”,这里虽然对象地址不相等,但是内容相等,所以同样返回true。

这里我就想给各位出个典型的String例子了:

public static void main(String[] args) {       String a = "宜春";       String b = new String("宜春");       String c = b; //注意这里是引用传递,意思是c也指向b指向的内存地址              System.out.println(a == b);  //false       System.out.println(a == c);  //false       System.out.println(b == c);  //true       System.out.println(a.equals(b));  //true       System.out.println(a.equals(c));  //true       System.out.println(b.equals(c));  //true    }
【特别注意:String类型属于引用类型】

解析:(1)a == b?意思是地址指向的是同一块地方吗?很明显不一样。

(2)a == c?意思是地址指向的是同一块地方吗?很明显不一样。

(3)b == c?意思是地址指向的是同一块地方吗?很明显内容一样,所以为true。

(4)a.equals( b )?意思是地址指向的内容一样嘛?一样。

(4)a.equals( c )?意思是地址指向的内容一样嘛?一样。

(4)b.equals( c )?意思是地址指向的内容一样嘛?一样。

当然,你可能还是有点疑惑,那么结合下面这张图再理解上面的解析,你可能就恍然大悟了

998391e7c610bd4462fac23ddf503193.png

OK。现在能理解嘛?你你你......不用回答,我知道你理解了(理直气壮)。当然值得注意一点的是String中intern()方法,先看一段程序:

public static void main(String[] args) {       String a = "宜春";       String b = new String("宜春");       b=b.intern();       System.out.println(a == b);  //true       System.out.println(a.equals(b));  //true    }

intern方法的意思是检查字符串池里是否存在,如果存在了那就直接返回为true。因此在这里首先a会在字符串池里面有一个,然后 b.intern()一看池子里有了,就不再新建new了,直接把b指向它。

3、为什么要重写equals方法?

不知道大家有没有想过这个问题。当然答案也是很简单的,因为程序员比较字符串一般比较其内容就好了,比较内存地址是不是同一个对象就好像没啥意义了,重写equals方法就很方便用来比较字符串的内容了。

其实除了诸如String、Date等类对equals方法进行重写,我们在实际开发中,我们也常常会根据自己的业务需求重写equals方法.

举个栗子:我们的需求就是如果两个学生对象姓名、身份证号、性别相等,我们认为两个学生对象相等,不一定需要学生对象地址相同。

学生A的个人信息(姓名:如花,性别:女,身份证号:123,住址:广州),学生A对象地址为0x11, 学生B的个人信息(姓名:如花,性别:女,身份证号:123,住址:深圳),学生A对象地址为0x12,

这时候如果不重写Object的equals方法,那么返回的一定是false不相等,这个时候就需要我们根据自己的需求重写equals()方法了。具体equals方法的重写代码如下:

// 重写equals方法   @Override   public boolean equals(Object obj) {     if(!(obj instanceof Student)) {       // instanceof 已经处理了obj = null的情况          return false;       }       Student stuObj = (Student) obj;     // 对象地址相等       if (this == stuObj) {           return true;        }       // 如果两个对象姓名、身份证号码、性别相等,我们认为两个对象相等       if (stuObj.name.equals(this.name) && stuObj.sex.equals(this.sex) && stuObj.IDnumber.equals(this.IDnumber)) {            return true;        } else {            return false;       }   }

开发中这样设计,才能符合我们的生活!到这里我就不信了你还搞不定==和equals!

可是一涉及重写equals方法的同时又衍生了下面一个问题。

4、重写equals方法之后要不要重写hashCode()方法?

当然这个问题要讨论,又要长篇大论哔哔一大堆了,有空写一篇这样的文章吧专门讨论讨论这个问题,当然园子里的大佬们也写了一大堆!可以自行去了解了解。本篇文章简单聊聊,点到即可。

首先hashCode()方法是Object类的一个方法,源码如下:

/**     * Returns a hash code value for the object. This method is     * supported for the benefit of hash tables such as those provided by     * {@link java.util.HashMap}.     * <p>     * The general contract of {@code hashCode} is:     * <ul>     * <li>Whenever it is invoked on the same object more than once during     *     an execution of a Java application, the {@code hashCode} method     *     must consistently return the same integer, provided no information     *     used in {@code equals} comparisons on the object is modified.     *     This integer need not remain consistent from one execution of an     *     application to another execution of the same application.     * <li>If two objects are equal according to the {@code equals(Object)}     *     method, then calling the {@code hashCode} method on each of     *     the two objects must produce the same integer result.     * <li>It is <em>not</em> required that if two objects are unequal     *     according to the {@link java.lang.Object#equals(java.lang.Object)}     *     method, then calling the {@code hashCode} method on each of the     *     two objects must produce distinct integer results.  However, the     *     programmer should be aware that producing distinct integer results     *     for unequal objects may improve the performance of hash tables.     * </ul>     * <p>     * As much as is reasonably practical, the hashCode method defined by     * class {@code Object} does return distinct integers for distinct     * objects. (This is typically implemented by converting the internal     * address of the object into an integer, but this implementation     * technique is not required by the     * Java<font size="-2"><sup>TM</sup></font> programming language.)     *     * @return  a hash code value for this object.     * @see     java.lang.Object#equals(java.lang.Object)     * @see     java.lang.System#identityHashCode     */    public native int hashCode();

可以看出hashCode()方法返回的就是一个int数值,从方法的名称上就可以看出,其目的是生成一个hash码。hash码的主要用途就是在对对象进行散列的时候作为key输入,据此很容易推断出,我们需要每个对象的hash码尽可能不同,这样才能保证散列的存取性能。

事实上,Object类提供的默认实现确实保证每个对象的hash码不同(在对象的内存地址基础上经过特定算法返回一个hash码)。Java采用了哈希表的原理。哈希算法也称为散列算法,是将数据依特定算法直接指定到一个地址上。初学者可以这样理解,hashCode方法实际上返回的就是对象存储的物理地址(实际上不是)。

想要知道hashCode的作用,必须要先知道Java中的集合。

Java中的集合List的元素是有序的,元素可以重复;Set元素无序,但元素不可重复。这我们都清楚。但是你有没有想过这样一个问题:要想保证元素不重复,可两个元素是否重复应该依据什么来判断呢?

每错这里就是用Object.equals方法了。但是,如果每增加一个元素就检查一次,那么当元素很多时,后添加到集合中的元素比较的次数就非常多了。也就是说,如果集合中现在已经有1000个元素,那么第1001个元素加入集合时,它就要调用1000次equals方法。这显然会大大降低效率。

那怎么解决呢?我们可以在Java集合框架中得到验证。由于HashSet是基于HashMap来实现的,所以这里只看HashMapput方法即可。源码如下:

public V put(K key, V value) {        if (table == EMPTY_TABLE) {            inflateTable(threshold);        }        if (key == null)            return putForNullKey(value);        int hash = hash(key);        //这里通过哈希值定位到对象的大概存储位置        int i = indexFor(hash, table.length);        for (Entry<K,V> e = table[i]; e != null; e = e.next) {            Object k;            //if语句中,先比较hashcode,再调用equals()比较            //由于“&&”具有短路的功能,只要hashcode不同,也无需再调用equals方法            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {                V oldValue = e.value;                e.value = value;                e.recordAccess(this);                return oldValue;            }        }        modCount++;        addEntry(hash, key, value, i);        return null;}

正如源码中注释所述,“&&”具有短路的功能,只要hashcode不同,也无需再调用equals方法。是的,Java采用了哈希表的原理。 哈希表具有优越的查询性能,就像九九乘法表2*3=6你能很轻易知道,但是哈希表难免还会出现哈希冲突,只是概率极低。

如此设计,这样一来,当集合要添加新的元素时,先调用这个元素的hashCode方法,就一下子能定位到它应该放置的物理位置上。如果这个位置上没有元素,它就可以直接存储在这个位置上,不用再进行任何比较了;如果这个位置上已经有元素了,就调用它的equals方法与新元素进行比较,相同的话就不存,不相同就散列其它的地址。所以这里存在一个冲突解决的问题。这样一来实际调用equals方法的次数就大大降低了,几乎只需要一两次。

因此并不是重写了equals方法就一定要重写hashCode方法,只有用到HashMap,HashSet等Java集合的时候重写了equals方法就一定要重写hashCode方法。用不到哈希表仅仅重写equals()方法也OK的。

Java官方建议 重写equals()就一定要重写hashCode()方法。毕竟实际开发场景中常常用到Java集合

5、eqauls方法和hashCode方法关系

Java对于eqauls方法和hashCode方法是这样规定的:

1、如果两个对象equals为true ,他们的hashcode一定相等。2、如果两个对象equals为false,他们的hashcode有可能相等。3、如果两个对象hashcode相等,equals不一定为true。4、如果两个对象hashcode不相等,equals一定为false。

最后,若有不足或者不正之处,欢迎指正批评,感激不尽!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/488680.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java八股 spring + mybatis

Spring常用注解&#xff08;绝对经典&#xff09;_spring注解-CSDN博客 框架篇-02-Spring-单例bean是线程安全的吗_哔哩哔哩_bilibili 1.spring.bean 单例 线程不安全 2.AOP 项目里可以说记录用户登录日志&#xff0c;利用request去获取姓名、ip、、请求方式、url&#xff0…

服务器数据库2008怎么备份数据库文件,怎么备份SQL Server2008数据库

在使用SQL Server 2008服务器的时候&#xff0c;我们需要定时的备份数据库来防止数据的丢失&#xff0c;下面学习啦小编为大家介绍备份SQL Server 2008数据库的方法。备份SQL Server 2008数据库的方法在开始菜单中点击“SQL Server Management Studio”在弹出的界面点击连接&am…

蝙蝠为啥这么厉害?地球人整明白了没有?

来源&#xff1a;周末八点半公元一世纪的时候&#xff0c;希腊的普鲁塔克提出了一个问题&#xff1a;如果忒修斯船上的零件被逐渐替换&#xff0c;直到所有的零件都不是原来的零件&#xff0c;那么这艘船还是原来的那艘船吗&#xff1f;这就是人类历史上的忒修斯悖论&#xff0…

vant input框禁止调用手机键盘_春运不要变“泰囧”手机这些功能让回家的路更安全...

随着春节的临近&#xff0c;年味儿可以说是越来越浓了&#xff0c;比如刚刚开始的支付宝集五福活动激发了大家的参与热情&#xff0c;而每年都会上热搜的春运更是成为了我国人民过年最真实的写照。就拿小编来说&#xff0c;作为一个张家口的北漂人&#xff0c;前几天京张高铁的…

math python 向上取整_Python成为专业人士笔记-各数学运算操作深度剖析

“专业人士笔记”系列目录&#xff1a;创帆云&#xff1a;Python成为专业人士笔记--强烈建议收藏&#xff01;每日持续更新&#xff01;​zhuanlan.zhihu.comPython可以执行常见的数学运算符&#xff0c;包括整数和浮点除法、乘法、取幂、加法和减法&#xff0c;而数学math模块…

css3 shapes是什么意思,如何在Web中使用CSS Shapes

布局一般都是遵循按行和列等线性原则&#xff0c;Web网站的布局到今天为止很大程度上受到这些原则的影响。虽然CSS Grid的出现让布局变得更好&#xff0c;更灵活&#xff0c;但相对于印刷媒体而言&#xff0c;Web布局总体上还是受到很好的限制&#xff0c;特别是内容流上。杂志…

wps临时文件不自动删除_电脑:让 Windows 10 系统自动清理临时文件

不少朋友在系统用久了以后&#xff0c;都会用一些软件来帮忙清理系统中没用的文件&#xff0c;其中包括一些临时文件、无用文件等。但其实在 Windows 10 中&#xff0c;系统已经内置了自动定期清理临时文件的功能了。你还不知道&#xff1f;跟着我们来学习下吧。这个功能就隐藏…

服务器系统gho系统怎么安装系统,GHOST怎么重装系统?GHO文件安装系统教程

ghost映像文件就是系统文件&#xff0c;通过gho文件我们可以就进行系统的重装。不过对于电脑小白来说&#xff0c;不知道在哪里可以下载纯净的ghost文件&#xff0c;下载完成后也不清楚如何使用gho文件安装系统。那么下面就让小编教大家使用gho文件重装系统。相关教程&#xff…

Science | 谷岩/王朗团队揭示大脑中的免疫细胞竟是记忆遗忘的“主谋”

来源&#xff1a;BioArt记忆是大脑最重要的功能之一&#xff0c;也是人类研究最多的脑功能之一。记忆随时在发生&#xff0c;而遗忘如影随形。海马体位于大脑丘脑和内侧颞叶之间&#xff0c;是负责记忆的编码和存储的一个重要脑区。在这里&#xff0c;记忆信息被编码于一些神经…

基于深层卷积网络的手写数字识别 minist_「Tensorflow」基于CNN的数字OCR识别

导读 对于人类来说&#xff0c;识别手写的数字是一件非常容易的事情。我们甚至不用思考&#xff0c;就可以看出下面的数字分别是1&#xff0c;2&#xff0c;3。那机器如何来识别数字&#xff1f;本期将使用Tensorflow搭建卷积神经网络&#xff0c;进行手写数字的识别。代码可关…

2019年5G创新深度研究报告

来源&#xff1a;中信建投从历史上看&#xff0c;每一轮科技产业创新周期均主要由通信代际升级驱动&#xff0c;历时 5-8 年。我们认为 2017-2019 年为 4G 时代的稳定成熟期&#xff0c;而进入 2020 年&#xff0c;运营商加速投入 5G 网络建设&#xff0c;科技软硬件有望在运营…

鹰眼系统原理_山东首家露天焚烧鹰眼监控系统在我镇投入使用

露天冒烟着火&#xff0c;不用人员到现场&#xff0c;电子围栏就会锁定目标&#xff0c;自动报警&#xff0c;提醒监管人员立即现场处置。日前&#xff0c;莱西市院上镇新安装建设的污染源鹰眼监控系统投入使用&#xff0c;实现了环境监控全方位、自动化。据了解&#xff0c;这…

机器人的工作原理,这是我见过最详细的解析!

来源&#xff1a;网络很多人一听到“机器人”这三个字脑中就会浮现“外形酷炫”、“功能强大”、“高端”等这些词&#xff0c;认为机器人就和科幻电影里的“终结者”一样高端炫酷。其实不然&#xff0c;在本文中&#xff0c;我们将探讨机器人学的基本概念&#xff0c;并了解机…

linux mint 图标主题_如何在 Linux Mint 中更换主题

一直以来&#xff0c;使用 Cinnamon 桌面环境的 Linux Mint 都是一种卓越的体验。这也是为何我喜爱 Linux Mint的主要原因之一。-- Its Foss&#xff08;作者&#xff09;一直以来&#xff0c;使用 Cinnamon 桌面环境的 Linux Mint 都是一种卓越的体验。这也是为何我喜爱 Linux…

服务器物品展示框刷物品,我的世界1period;11period;2展示框刷物品bug | 手游网游页游攻略大全...

发布时间&#xff1a;2017-09-25我的世界惊现全新无限刷物品bug 服主大大都要注意了.那今天给大家分享一个玩家无意间发现的新的无限刷物品bug,而且还是在服务器中哦!那感兴趣的玩家不妨进来看看哦! 在一个rpg服务器玩 开小号召唤boss的时候发现的. ...标签&#xff1a;我的世界…

Nature:揭示人大脑类器官为何缺乏正常人脑特有的细胞亚型和复杂回路

来源&#xff1a;生物谷作为在实验室中通常利用人类干细胞培育出的大脑样组织三维球体&#xff0c;大脑类器官被吹捧为有潜力让科学家们在受控的实验室条件下研究大脑回路的形成。关于大脑类器官的讨论非常热闹&#xff0c;一些科学家认为它们将使得快速开发针对破坏性的脑部疾…

anaconda 怎么安装xlrd_Pyinstaller打包,文件太大了怎么办?

这是一个很长的故事&#xff0c;嫌长的直接看最后的结论事情经过上周接了个需求&#xff0c;写了个小工具给客户&#xff0c;他要求打包成exe文件&#xff0c;这当然不是什么难事。因为除了写Python的&#xff0c;绝大多数人电脑里都没有Python编译器&#xff0c;所以打包成exe…

android checkbox 选中事件_使用Vue3.0新特性造轮子 WidgetUI3.0 (Checkbox复选框组件)

"title"标题示例代码&#xff1a;data [ { title: 新日小卫士二代, }, { title: 车子质量不合格, }, { title: 我买的骑士1号仪表台进水怎么回事&#xff1f;, }, { title: 风雅欧妮大灯高低调节, }]"title"标题和"desc"描…

服务器装系统用哪个好,服务器系统重装用哪个系统

服务器系统重装用哪个系统 内容精选换一换华为云帮助中心&#xff0c;为用户提供产品简介、价格说明、购买指南、用户指南、API参考、最佳实践、常见问题、视频帮助等技术文档&#xff0c;帮助您快速上手使用华为云服务。重装裸金属服务器的操作系统。快速发放裸金属服务器支持…

2020图机器学习GNN的四大研究趋势

来源&#xff1a;专知【导读】以图神经网络为代表的图机器学习在近两年成为研究热点之一。近日&#xff0c;图机器学习专家 Sergei Ivanov 为我们解读了他总结出来的 2020 年图机器学习的四大热门趋势&#xff0c;包括图神经网络的理论理解、应用普及、应用、图嵌入框架&#x…