一、前言:

equals和==和hashcode是java中的基础中的基础,但是确实容易被问到,而且因为工作中经常用所以很容易在复习时遗漏掉,这几天面了个大厂就在这个问题上翻车了,不仅记混了,而且很坚信自己记混的答案,好在其他问题答的不错,加上面试官容忍度高放过一马,所以今天也就详细整理了下它们三个的恩怨情仇

二、【==】双等号

【==】其实没那么复杂,它的功能就只是比较两边的值是否相等。只是如果变量是引用类型Integer、String、Object)的话,比较的就是内存地址,因为引用类型变量存的值就是对象的地址而已。而基本类型int、double)的变量存的就是它们的值,和内存地址什么的无关。

所以我们在用【==】比较引用类型的变量时,就麻烦了。如果引用类型是Integer、String、Long这种,我们比较它的时候肯定是打算比较它们代表的值,而不是比较什么内存地址。

三、equals方法:

equals()是Object类的方法,而Object类又是所有类的祖宗(父类),所以所有的引用类型都有equals()方法。但是有很多类都会重新equals以及hashcode方法

1.object类的equals

先看下object的equals方法

   public boolean equals(Object obj) {return (this == obj);}

object类的equals方法很简单其实就是【==】

2.Integer类的equals

可以看出Integer类的equals方法其实时比较的值

 public boolean equals(Object obj) {if (obj instanceof Integer) {return value == ((Integer)obj).intValue();}return false;}

3.String类的equals方法

public boolean equals(Object anObject) {//判断引用if (this == anObject) {return true;}//判断是否是Stringif (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;}

大概流程是:

(1)判断引用是否相等

(2)判断是否是String

(3)判断字符长度是否相等

(4)遍历判断每个字符是否相等

四、==和equals的区别

如果是基本类型,只能用【==】,它们没有equals方法。

如果是引用类型,直接【==】的话是比较内存地址。如果这个引用类型重写过equals()方法,可以用equals()方法比较内容,如Integer、String……等常用的引用类型都是有重写过euqals()的。

五、int、Integer和new Integer()多种赋值比较区别

1.int

int无需多说,基本类型,无论是声明变量还是==比较我们都很清楚了,都只是比较值而已。

2.Integer

Integer的初始化就不太一样了

Integer i = 10;
Integer j = 10;
System.out.println(i==j);

如果这么进行赋值,那么返回是true,按照之前的说法比较的是地址那么必然是不一样的才对啊,这里就涉及了java自动装箱

系统会自动将赋给Integer变量的int值封装成一个Integer对象,例如Integer a1=3,实际上的操作是

Integer a = Integer.valueof(3)

但是这个自动装箱也是有范围限制的,当int的范围在-128——127之间时,会通过一个IntegerCache缓存来创建Integer对象;当int不在该范围时,就直接是new Integer()创建对象

3.new Integer()

这种赋值就不用多说了,等号会比较引用,所以不会相等

4.其他包装类

例如Long和Integer是一样的,有一个-128~127的缓存,Double和Float则是没有缓存直接返回new。

六、String直接赋值和new String()比较的区别

String也需要特别的说明一下,因为它并不属于基本类型,所以没有int、long那种类型,这种情况我们只需要比较两种情况,直接赋值和new,也就是比较:

//第一组
String a=new String("test");
String b="test";
System.out.println(a==b);//第二组
System.out.println("a"=="a");//第三组String a=new String("test");
String b=new String("test");
System.out.println(a ==b);

答案是 false,true,false,因为只要有一边是new的方式初始化的变量,那地址肯定是不一样的,并且这里也是用【==】进行比较地址,自然是false。

字符串常量池

关于String的直接赋值,则需要先说明一下字符串常量池。

String类是我们平时项目中使用的很多的对象类型,jvm为了提升性能和减少内存开销,以及避免字符的重复创建,专门维护了一块字符串常量池的内存空间。当我们需要使用字符串时,就会先去这个常量池中找,如果存在该字符串,就直接将该字符串的地址返回去直接用。如果不存在,则用new进行初始化并将这个字符串投入常量池中以供后面使用。

这个字符串常量池就是通过直接赋值时使用的,所以如果是直接赋值的方式初始化相同内容的String,那么其实都是从同一个常量池里取到字符串,地址指向的是同一个对象,自然结果都是相同的。

字符串的拼接比较

String a = "hello";
String d = "helloworld";
final String c = "hello";
System.out.println(d == a + "world");          //false
System.out.println(d == "hello" + "world");    //true
System.out.println(d == c + "world");          //false

如果只看内容,d都是和helloworld进行了比较,但是带有变量的就是false,纯字符串的就是true,这是为什么呢?

其实这跟jvm的编译期有关,在进行编译时,它可以识别出"hello" + “world"这样的字面量和"helloworld"是相同的,认为这是直接的字面量赋值。通过反编译其实可以看出来,编译后,它直接将"hello” + “world"编译成了"helloworld”。所以自然都是在同一个常量池里找,比较起来也是相同的。

但是加上final就有不一样了,这里由于c被视为了常量,所以同样认为是字面量赋值,最终还是在常量池中获取的值,结果就是true了。

如果有任一边是通过new赋值的,那么结果肯定是false。

如果两边都是直接赋值的,或是通过final变量进行拼接赋值的,结果是true。只要有一边有涉及非final变量,结果就是false。

七、 hashCode()

1.简介:

hashCode()方法的作用是获取哈希码,也称为散列码,它实际上只是返回一个int整数。

但是它主要是应用在散列表中,如:HashMap,Hashtable,HashSet,在其他情况下一般没啥用,原因后面会说明。

Java中的hashCode并没有真正的实现为每个对象生成一个唯一的hashCode,还是会有一定的重复几率。

object中的hashcode()

public native int hashCode();

2.重写hashCode()

核心是保证相同的对象能返回相同的hash值,尽量做到不同的对象返回不同的hash值。主要能保证核心的规则即可。例如Integer的hashcode就很简单粗暴,直接返回它所代表的的value值。也就是1的hashcode还是1,100的hashcode还是100。

    public int hashCode() {return Integer.hashCode(value);}

String 的hashCode就相对复杂一些了通过这个公式计算的hashcode

s[0]*31^(n-1) + s[1]*31^(n-2) + … + s[n-1]

    public int hashCode() {int h = hash;if (h == 0 && value.length > 0) {char val[] = value;for (int i = 0; i < value.length; i++) {h = 31 * h + val[i];}hash = h;}return h;}

在java的很多类中都会重写equals和hashCode方法,这是为什么呢?比如我定义两个字符相同的字符串,那么对它们进行比较时,我想要的结果应该是相等的,如果你不重写equals和hashCode方法,他们肯定是不会相等的,因为两个对象的内存地址不一样。

3.hashCode()和equals() 的关系

和equal()方法作用类似,hashCode()在java中的也是用于比较两个对象是否相等。我们应该都大概听过一句话:重写equals()方法的话一定要重写hashCode()。这里就说明一下这点。

分两种情况:

(1)首先一种情况是确定了不会创建散列表的类,我们不会创建这个类的HashSet、HashMap集合之类的。这种情况下,这个类的hashCode()和equals() 完全没有任何关系,当我们比较这个类的两个对象时,直接用的就是equals(),完全用不上hashCode()。自然,也没啥必要重写。

(2)另一种情况自然就是可能会需要使用到散列表的类了,这里hashCode()和equals()就比较有关系了:

在散列表的使用中,经常需要大量且快速的对比,例如你每次插入新的键值对,它都必须和前面所有的键值对进行比较,确保你没有插入重复的键。这样如果每个都用equals,可想而知,性能是十分可怕的。如果你的equals再复杂一些,那就凉凉了。

这时候就需要hashCode()了,如果利用hashCode()进行对比,只要生成一个hash值比较数字是否相同就可以了,能显著的提高效率。但是虽然如此,原本的equals()方法还是需要的,hashCode()虽然效率高,可靠性却不足,有时候不同的键值对生成的hashcode也是一样的,这就是哈希冲突。

在使用时,hashCode()将与equals结合使用。虽然hashcode可能会让不同的键产生相同的hashcode,但是它能确保相同的对象返回的hashcode一定是相同的(除非你重写没写好),我们只需要利用后面这点,一样可以提高效率。

在散列表中进行对比时,先比较hashCode(),如果它不相等,那说明两个对象肯定不可能相同,就可以直接进行下一个比较了。但如果hashCode()相同,因为哈希冲突的缘故我们无法直接判断两个对象是相同的,就必须继续比较equals()来获取可靠的结果。

所以如果这个类可能会创建散列表的情况下,重写了equals方法,就必须重写配套的hashcode方法,他们两个在散列表中是搭配使用的。

equals和==和hashcode的恩怨情仇相关推荐

  1. 漫画:前端发展史的江湖恩怨情仇

    作者 | 前端布道师 来源 | 前端布道师(ID:honeyBadger8) 时间总是过得很快, 似乎快得让人忘记了昨天,前端WEB领域的发展更是如此,转眼间已是近30年,时光荏苒,初心不变,在一代又 ...

  2. 宏观与量子的恩怨情仇

    第四章:宏观与量子的恩怨情仇 我们知道哥本哈根诠释由波尔和海森堡于1927年在哥本哈根合作研究时共同提出的.此诠释建立在由德国数学家.物理学家Max Born所提出的"波函数的概率表达&qu ...

  3. [你必须知道的.NET]第一回:恩怨情仇:is和as

    本文将介绍以下内 容: • 类型转换 • is/as操作符小议 1. 引言 类型安全是.NET设计之初重点考虑 的内容之一,对于程序设计者来说,完全把握系统数据的类型安全,经常是力不从心的问题.现在, ...

  4. java重写6,java重写equals()方法和hashCode()方法

    1.equals()方法和hashCode()方法是什么? equals()和hashCode()都是是Java中万物之源Object类中的方法: equals方法用于比较两个对象是否相同,Objec ...

  5. [你必须知道的.NET] 第一回:恩怨情仇:is和as

    发布日期:2007.4.7 作者:Anytao ©2007 Anytao.com 转贴请注明出处,留此信息. 本文将介绍以下内容: • 类型转换 • is/as操作符小议 1. 引言 类型安全是.NE ...

  6. JAVA正确地自定义比较对象---如何重写equals方法和hashCode方法

    在实际应用中经常会比较两个对象是否相等,比如下面的Address类,它有两个属性:String province 和 String city. public class Address {privat ...

  7. 重写equals()时为什么也得重写hashCode()之深度解读equals方法与hashCode方法渊源

    重写equals()时为什么也得重写hashCode()之深度解读equals方法与hashCode方法渊源 在使用Map接口时,我们的愿望是当key1.equals(key2)时,它们获取的valu ...

  8. 详解 equals() 方法和 hashCode() 方法

    来源:编程迷思, www.cnblogs.com/kismetv/p/7191736.html 前言 Java的基类Object提供了一些方法,其中equals()方法用于判断两个对象是否相等,has ...

  9. 红帽 与 CentOS 之间的恩怨情仇

    [CSDN 编者按]红帽正式宣布 CentOS 8 于 2021年底结束支持,后续将由 CentOS Stream 接班.一起来看看红帽与 CentOS 的"恩怨情仇"-- 参考链 ...

最新文章

  1. libc.so.6 is needed by mysql_libc.so.6(GLIBC_2.14)(64bit) is needed by…问题的解决办法
  2. LabVIEW保存、读取配置文件
  3. pta 7-3 两个有序链表序列的合并 (20 分)
  4. AI会率先在汽车、安全和金融领域落地!不服来辩 | AI科技评论
  5. 机器学习实战(八)预测数值型数据:回归
  6. 【ICCV2019】完整论文列表
  7. 草稿 12月第2周 排课
  8. ExtJs2.0学习系列(4)--Ext.FormPanel之第一式
  9. ICCV 2021 oral 重构+预测,双管齐下提升视频异常检测性能
  10. 中国企业借东博会“走出去”将打造马来西亚首个智慧城市
  11. iOS - Swift NSUserDefaults 数据存储
  12. 调用百度API实现人像动漫化(C++)
  13. yaml和properties文件相互转换的网站
  14. android代码修改view的宽度,代码动态改变view的大小
  15. 【复习】物联网导论知识梳理
  16. vs2019(C语言) 使用教程
  17. 也谈谈内卷化、996和程序员的发展
  18. 数独大师级技巧_数独入门:你必须掌握的那些规则和技巧
  19. JSP SSH校园兼职信息发布平台myeclipse开发mysql数据库MVC模式java编程计算机网页设计
  20. jedis 源码阅读二——jedisPool

热门文章

  1. css属性选择器诸如Class^=,Class*= ,Class$=释义
  2. 景德镇人都应该知道的一个历史人物--唐英
  3. 做一个派发工单的微信小程序
  4. 我的QQ微博 和新浪微博地址
  5. 【零基础学习服装设计】服装色彩搭配试听课_豆瓣
  6. springboot中配置logback实现打印控制台、写出文件,控制日志级别的方式
  7. matlab进行电机仿真,MATLAB simulink在电机中的仿真.ppt
  8. Proteus仿真时出现Cannot open‘***\LISA5476.SDF’的错误!
  9. kong网关使用记录
  10. Asp.net Ajax WebService 实现循环引用(自定义JavascriptConverter)