问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501
你好,欢迎来到懂视!登录注册
当前位置: 首页 - 正文

java里equals和hashCode之间什么关系

发布网友 发布时间:2022-04-25 21:41

我来回答

5个回答

热心网友 时间:2022-06-17 18:34

equals与hashcode的关系是:

两个对象在equals相等的情况下,hashcode有可能相等也有可能不相等,

而两个对象在hashcode不相等的情况下,equals也必定不相等。

理解equals的应用:它是用于用户在进行对比的时候,这个时候对比的是内容是否相等

理解hashcode的应用:例如set集合,它的不可重复,进行对比的便是hashcode是否相等,因此set集合实现了不可重复。

如果根据 equals(Object) 方法,两个对象是相等的,那么对这两个对象中的每个对象调用 hashCode 方法都必须生成相同的整数结果。

即使两个hashCode()返回的结果相等,两个对象的equals方法也不一定相等。

扩展资料:

equals:

电脑编程语言,被用来检测两个对象是否相等,即两个对象的内容是否相等。

equals 方法(是String类从它的超类Object中继承的)

==用于比较引用和比较基本数据类型时具有不同的功能:

比较基本数据类型,如果两个值相同,则结果为true

而在比较引用时,如果引用指向内存中的同一对象,结果为true

hashCode:

是jdk根据对象的地址或者字符串或者数字算出来的int类型的数值。

支持此方法是为了提高哈希表(例如 java.util.Hashtable 提供的哈希表)的性能。

HashMap对象是根据其Key的hashCode来获取对应的Value。

在重写父类的equals方法时,也重写hashcode方法,使相等的两个对象获取的HashCode也相等。

这样当此对象做Map类中的Key时,两个equals为true的对象其获取的value都是同一个,比较符合实际。

参考资料:

百度百科 ------ hashcode

百度百科 ------ equals

热心网友 时间:2022-06-17 18:35

equals方法
若不覆写则默认调用的是object的equals方法,默认比较的是对象的地址。

需要满足以下几个条件
自反性
对称性
传递性
一致性
非空性
实现高质量equals方法的诀窍:
1.使用==符号检查“参数是否为这个对象的引用”。如果是,则返回true。这只不过是一种性能优化,如果比较操作有可能很昂贵,就值得这么做。
2.使用instanceof操作符检查“参数是否为正确的类型”。如果不是,则返回false。一般来说,所谓“正确的类型”是指equals方法所在的那个类。
3.把参数转换成正确的类型。因为转换之前进行过instanceof测试,所以确保会成功。
4.对于该类中的每个“关键”域,检查参数中的域是否与该对象中对应的域相匹配。如果这些测试全部成功,则返回true;否则返回false。
5.当编写完成了equals方法之后,检查“对称性”、“传递性”、“一致性”。
hashcode
1、如果两个对象equals,Java运行时环境会认为他们的hashcode一定相等。
2、如果两个对象不equals,他们的hashcode有可能相等。
3、如果两个对象hashcode相等,他们不一定equals。
4、如果两个对象hashcode不相等,他们一定不equals。

关于这两个方法的重要规范:
规范1:若重写equals(Object obj)方法,有必要重写hashcode()方法,确保通过equals(Object obj)方法判断结果为true的两个对象具备相等的hashcode()返回值。说得简单点就是:“如果两个对象相同,那么他们的hashcode应该相等”。不过请注意:这个只是规范,如果你非要写一个类让equals(Object obj)返回true而hashcode()返回两个不相等的值,编译和运行都是不会报错的。不过这样违反了Java规范,程序也就埋下了BUG。
规范2:如果equals(Object obj)返回false,即两个对象“不相同”,并不要求对这两个对象调用hashcode()方法得到两个不相同的数。说的简单点就是:“如果两个对象不相同,他们的hashcode可能相同”。

5、为什么覆盖equals时总要覆盖hashCode
一个很常见的错误根源在于没有覆盖hashCode方法。在每个覆盖了equals方法的类中,也必须覆盖hashCode方法。如果不这样做的话,就会违反Object.hashCode的通用约定,从而导致该类无法结合所有基于散列的集合一起正常运作,这样的集合包括HashMap、HashSet和Hashtable。
1.在应用程序的执行期间,只要对象的equals方法的比较操作所用到的信息没有被修改,那么对这同一个对象调用多次,hashCode方法都必须始终如一地返回同一个整数。在同一个应用程序的多次执行过程中,每次执行所返回的整数可以不一致。
2.如果两个对象根据equals()方法比较是相等的,那么调用这两个对象中任意一个对象的hashCode方法都必须产生同样的整数结果。
3.如果两个对象根据equals()方法比较是不相等的,那么调用这两个对象中任意一个对象的hashCode方法,则不一定要产生相同的整数结果。但是程序员应该知道,给不相等的对象产生截然不同的整数结果,有可能提高散列表的性能。

6、总结:
1、equals方法用于比较对象的内容是否相等(覆盖以后)
2、hashcode方法只有在集合中用到
3、当覆盖了equals方法时,比较对象是否相等将通过覆盖后的equals方法进行比较(判断对象的内容是否相等)。
4、将对象放入到集合中时,首先判断要放入对象的hashcode值与集合中的任意一个元素的hashcode值是否相等,如果不相等直接将该对象放入集合中。如果hashcode值相等,然后再通过equals方法判断要放入对象与集合中的任意一个对象是否相等,如果equals判断不相等,直接将该元素放入到集合中,否则不放入。

另外再说一下==
对于引用对象来说,比较的是对象的地址。对于基础类型,比较的是值

热心网友 时间:2022-06-17 18:35

1.
首先equals()和hashcode()这两个方法都是从object类中继承过来的。
equals()方法在object类中定义如下:
public
boolean
equals(Object
obj)
{
return
(this
==
obj);
}
很明显是对两个对象的地址值进行的比较(即比较引用是否相同)。但是我们必需清楚,当String
、Math、还有Integer、Double。。。。等这些封装类在使用equals()方法时,已经覆盖了object类的equals()方法。比如在String类中如下:
public
boolean
equals(Object
anObject)
{
if
(this
==
anObject)
{
return
true;
}
if
(anObject
instanceof
String)
{
String
anotherString
=
(String)anObject;
int
n
=
count;
if
(n
==
anotherString.count)
{
char
v1[]
=
value;
char
v2[]
=
anotherString.value;
int
i
=
offset;
int
j
=
anotherString.offset;
while
(n--
!=
0)
{
if
(v1[i++]
!=
v2[j++])
return
false;
}
return
true;
}
}
return
false;
}
很明显,这是进行的内容比较,而已经不再是地址的比较。依次类推Double、Integer、Math。。。。等等这些类都是重写了equals()方法的,从而进行的是内容的比较。当然了基本类型是进行值的比较,这个没有什么好说的。
我们还应该注意,Java语言对equals()的要求如下,这些要求是必须遵循的:
??
对称性:如果x.equals(y)返回是“true”,那么y.equals(x)也应该返回是“true”。
??
反射性:x.equals(x)必须返回是“true”。
??
类推性:如果x.equals(y)返回是“true”,而且y.equals(z)返回是“true”,那么z.equals(x)也应该返回是“true”。
??
还有一致性:如果x.equals(y)返回是“true”,只要x和y内容一直不变,不管你重复x.equals(y)多少次,返回都是“true”。
??
任何情况下,x.equals(null),永远返回是“false”;x.equals(和x不同类型的对象)永远返回是“false”。
以上这五点是重写equals()方法时,必须遵守的准则,如果违反会出现意想不到的结果,请大家一定要遵守。
2.
其次是hashcode()
方法,在object类中定义如下:
public
native
int
hashCode();
说明是一个本地方法,它的实现是根据本地机器相关的。当然我们可以在自己写的类中覆盖hashcode()方法,比如String、Integer、Double。。。。等等这些类都是覆盖了hashcode()方法的。例如在String类中定义的hashcode()方法如下:
public
int
hashCode()
{
int
h
=
hash;
if
(h
==
0)
{
int
off
=
offset;
char
val[]
=
value;
int
len
=
count;
for
(int
i
=
0;
i
<
len;
i++)
{
h
=
31*h
+
val[off++];
}
hash
=
h;
}
return
h;
}
解释一下这个程序(String的API中写到):
s[0]*31^(n-1)
+
s[1]*31^(n-2)
+
...
+
s[n-1]
使用
int
算法,这里
s[i]
是字符串的第
i
个字符,n
是字符串的长度,^
表示求幂。(空字符串的哈希码为
0。)
首先,想要明白hashCode的作用,你必须要先知道Java中的集合。  
总的来说,Java中的集合(Collection)有两类,一类是List,再有一类是Set。
你知道它们的区别吗?前者集合内的元素是有序的,元素可以重复;后者元素无序,但元素不可重复。
那么这里就有一个比较严重的问题了:要想保证元素不重复,可两个元素是否重复应该依据什么来判断呢?
这就是Object.equals方法了。但是,如果每增加一个元素就检查一次,那么当元素很多时,后添加到集合中的元素比较的次数就非常多了。
也就是说,如果集合中现在已经有1000个元素,那么第1001个元素加入集合时,它就要调用1000次equals方法。这显然会大大降低效率。
于是,Java采用了哈希表的原理。哈希(Hash)实际上是个人名,由于他提出一哈希算法的概念,所以就以他的名字命名了。
哈希算法也称为散列算法,是将数据依特定算法直接指定到一个地址上。如果详细讲解哈希算法,那需要更多的文章篇幅,我在这里就不介绍了。
初学者可以这样理解,hashCode方法实际上返回的就是对象存储的物理地址(实际可能并不是)。
这样一来,当集合要添加新的元素时,先调用这个元素的hashCode方法,就一下子能定位到它应该放置的物理位置上。
如果这个位置上没有元素,它就可以直接存储在这个位置上,不用再进行任何比较了;如果这个位置上已经有元素了,
就调用它的equals方法与新元素进行比较,相同的话就不存了,不相同就散列其它的地址。
所以这里存在一个冲突解决的问题。这样一来实际调用equals方法的次数就大大降低了,几乎只需要一两次。
所以,Java对于eqauls方法和hashCode方法是这样规定的:
1、如果两个对象相同,那么它们的hashCode值一定要相同;2、如果两个对象的hashCode相同,它们并不一定相同
上面说的对象相同指的是用eqauls方法比较。
你当然可以不按要求去做了,但你会发现,相同的对象可以出现在Set集合中。同时,增加新元素的效率会大大下降。
3.这里我们首先要明白一个问题:
equals()相等的两个对象,hashcode()一定相等;
equals()不相等的两个对象,却并不能证明他们的hashcode()不相等。换句话说,equals()方法不相等的两个对象,hashcode()有可能相等。(我的理解是由于哈希码在生成的时候产生冲突造成的)。
反过来:hashcode()不等,一定能推出equals()也不等;hashcode()相等,equals()可能相等,也可能不等。解释下第3点的使用范围,我的理解是在object、String等类中都能使用。在object类中,hashcode()方法是本地方法,返回的是对象的地址值,而object类中的equals()方法比较的也是两个对象的地址值,如果equals()相等,说明两个对象地址值也相等,当然hashcode()也就相等了;在String类中,equals()返回的是两个对象内容的比较,当两个对象内容相等时,
Hashcode()方法根据String类的重写(第2点里面已经分析了)代码的分析,也可知道hashcode()返回结果也会相等。以此类推,可以知道Integer、Double等封装类中经过重写的equals()和hashcode()方法也同样适合于这个原则。当然没有经过重写的类,在继承了object类的equals()和hashcode()方法后,也会遵守这个原则。
4.谈到hashcode()和equals()就不能不说到hashset,hashmap,hashtable中的使用,具体是怎样呢,请看如下分析:
Hashset是继承Set接口,Set接口又实现Collection接口,这是层次关系。那么hashset是根据什么原理来存取对象的呢?
在hashset中不允许出现重复对象,元素的位置也是不确定的。在hashset中又是怎样判定元素是否重复的呢?这就是问题的关键所在,经过一下午的查询求证终于获得了一点启示,和大家分享一下,在java的集合中,判断两个对象是否相等的规则是:
1),判断两个对象的hashCode是否相等
如果不相等,认为两个对象也不相等,完毕
如果相等,转入2)
(这一点只是为了提高存储效率而要求的,其实理论上没有也可以,但如果没有,实际使用时效率会大大降低,所以我们这里将其做为必需的。后面会重点讲到这个问题。)
2),判断两个对象用equals运算是否相等
如果不相等,认为两个对象也不相等
如果相等,认为两个对象相等(equals()是判断两个对象是否相等的关键)
为什么是两条准则,难道用第一条不行吗?不行,因为前面已经说了,hashcode()相等时,equals()方法也可能不等,所以必须用第2条准则进行*,才能保证加入的为非重复元素。
比如下面的代码:
public
static
void
main(String
args[]){
String
s1=new
String("zhaoxudong");
String
s2=new
String("zhaoxudong");
System.out.println(s1==s2);//false
System.out.println(s1.equals(s2));//true
System.out.println(s1.hashCode());//s1.hashcode()等于s2.hashcode()
System.out.println(s2.hashCode());
Set
hashset=new
HashSet();
hashset.add(s1);
hashset.add(s2);
/*实质上在添加s1,s2时,运用上面说到的两点准则,可以知道hashset认为s1和s2是相等的,是在添加重复元素,所以让s2覆盖了s1;*/
Iterator
it=hashset.iterator();
while(it.hasNext())
{
System.out.println(it.next());
}
最后在while循环的时候只打印出了一个”zhaoxudong”。
输出结果为:false
true
-967303459
-967303459
这是因为String类已经重写了equals()方法和hashcode()方法,所以在根据上面的第1.2条原则判定时,hashset认为它们是相等的对象,进行了重复添加。
但是看下面的程序:
import
java.util.*;
public
class
HashSetTest
{
public
static
void
main(String[]
args)
{
HashSet
hs=new
HashSet();
hs.add(new
Student(1,"zhangsan"));
hs.add(new
Student(2,"lisi"));
hs.add(new
Student(3,"wangwu"));
hs.add(new
Student(1,"zhangsan"));
Iterator
it=hs.iterator();
while(it.hasNext())
{
System.out.println(it.next());
}
}
}
class
Student
{
int
num;
String
name;
Student(int
num,String
name)
{
this.num=num;
this.name=name;
}
public
String
toString()
{
return
num+":"+name;
}
}
输出结果为:
1:zhangsan
1:zhangsan
3:wangwu
2:lisi
问题出现了,为什么hashset添加了相等的元素呢,这是不是和hashset的原则违背了呢?回答是:没有
因为在根据hashcode()对两次建立的new
Student(1,"zhangsan")对象进行比较时,生成的是不同的哈希码值,所以hashset把他当作不同的对象对待了,当然此时的equals()方法返回的值也不等(这个不用解释了吧)。那么为什么会生成不同的哈希码值呢?上面我们在比较s1和s2的时候不是生成了同样的哈希码吗?原因就在于我们自己写的Student类并没有重新自己的hashcode()和equals()方法,所以在比较时,是继承的object类中的hashcode()方法,呵呵,各位还记得object类中的hashcode()方法比较的是什么吧!!
它是一个本地方法,比较的是对象的地址(引用地址),使用new方法创建对象,两次生成的当然是不同的对象了(这个大家都能理解吧。。。),造成的结果就是两个对象的hashcode()返回的值不一样。所以根据第一个准则,hashset会把它们当作不同的对象对待,自然也用不着第二个准则进行判定了。那么怎么解决这个问题呢??
答案是:在Student类中重新hashcode()和equals()方法。
例如:
class
Student
{
int
num;
String
name;
Student(int
num,String
name)
{
this.num=num;
this.name=name;
}
public
int
hashCode()
{
return
num*name.hashCode();
}
public
boolean
equals(Object
o)
{
Student
s=(Student)o;
return
num==s.num
&&
name.equals(s.name);
}
public
String
toString()
{
return
num+":"+name;
}
}
根据重写的方法,即便两次调用了new
Student(1,"zhangsan"),我们在获得对象的哈希码时,根据重写的方法hashcode(),获得的哈希码肯定是一样的(这一点应该没有疑问吧)。
当然根据equals()方法我们也可判断是相同的。所以在向hashset集合中添加时把它们当作重复元素看待了。所以运行修改后的程序时,我们会发现运行结果是:
1:zhangsan
3:wangwu
2:lisi
可以看到重复元素的问题已经消除。
关于在hibernate的pojo类中,重新equals()和hashcode()的问题:
1),重点是equals,重写hashCode只是技术要求(为了提高效率)
2),为什么要重写equals呢,因为在java的集合框架中,是通过equals来判断两个对象是否相等的
3),在hibernate中,经常使用set集合来保存相关对象,而set集合是不允许重复的。我们再来谈谈前面提到在向hashset集合中添加元素时,怎样判断对象是否相同的准则,前面说了两条,其实只要重写equals()这一条也可以。
但当hashset中元素比较多时,或者是重写的equals()方法比较复杂时,我们只用equals()方法进行比较判断,效率也会非常低,所以引入了hashcode()这个方法,只是为了提高效率,但是我觉得这是非常有必要的(所以我们在前面以两条准则来进行hashset的元素是否重复的判断)。
比如可以这样写:
public
int
hashCode(){
return
1;}//等价于hashcode无效
这样做的效果就是在比较哈希码的时候不能进行判断,因为每个对象返回的哈希码都是1,每次都必须要经过比较equals()方法后才能进行判断是否重复,这当然会引起效率的大大降低。
我有一个问题,如果像前面提到的在hashset中判断元素是否重复的必要方法是equals()方法(根据网上找到的观点),但是这里并没有涉及到关于哈希表的问题,可是这个集合却叫hashset,这是为什么??
我想,在hashmap,hashtable中的存储操作,依然遵守上面的准则。所以这里不再多说。这些是今天看书,网上查询资料,自己总结出来的,部分代码和语言是引述,但是千真万确是自己总结出来的。有错误之处和不详细不清楚的地方还请大家指出,我也是初学者,所以难免会有错误的地方,希望大家共同讨论。

热心网友 时间:2022-06-17 18:36

当比较2个实例变量是否是同一个对象时候,会先用equals比较是否相等,如果相等,再比较hashCode是否一致,如果一致就是同一个对象,如果不一致就是不同对象。

示例:

public class Student { //定义一个类
    @Override  
    public int hashCode() {//重写hashCode,都返回1
      return 1;
    }
    @Override  
    public boolean equals(Object obj) {  //重写equals,返回true
       return true;
    }        
}  
Student stu1 = new Student();
Student stu2 = new Student();
则这两个对象放入hashmap的时候是同一个对象,只能添加一个。
如果把上面equals方法改成返回false
@Override  
    public boolean equals(Object obj) {  //重写equals,返回false
       return false;
    }   
 则上面两个对象放入hashmap的时候是不同对象,添加的是2个。

热心网友 时间:2022-06-17 18:37

只是为了维护 hashCode 方法的常规协定,才要求用equals比较的两个对象的hashCode相同.

equals()和hashCode()都来自java.lang.Object.你当然可以重写.

比如a.equals(b).仅当a的内存地址相等时,才返回true.当然如String等类已经对这个方法进行了重写,比较的就不再是内存地址了.

hashCode()的值也是与内存地址相关的.所以仅当内存地址相等时,hashCode才相等.同样很多类也重写了这个方法,还是以String为例:
public int hashCode() {
int h = hash;
if (h == 0) {
int off = offset;
char val[] = value;
int len = count;

for (int i = 0; i < len; i++) {
h = 31*h + val[off++];
}
hash = h;
}
return h;
}
就不在与内存地址相关了.这样做是为了保证用equals比较返回为true的两个对象,他们的hashCode是相同的.

所以一般重写equals的时候都会重写hashCode().

当然,这个相当于一个约定,一个协议.你不这么做并不会错.
声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。
E-MAIL:11247931@qq.com
要一个带“长”字的成语 成语第二个字是长 预告登记有怎样的效力 ...他朋友借了三十万,现在还不出来,别人告他他会坐牢吗?我该不该借他... 欠网贷30万无力偿还,是否会坐牢? 寄快递什么意思 小配大出的小狗体型随谁狗狗生的小狗体型随谁 贝拉米奶粉最新事件有关于奶粉有问题的吗? 怀孕32周可以吃榴莲吗 榴莲的功效与作用 孕期31周能吃榴莲吗 联通云的块存储采用的存储机制是? Android中五中存储方式的区别和优劣性 数据存储的原理是什么 类对象的存储机制 米哈游的米游社被永久封号,还可以申诉解封吗如果可以,那申诉该说什么? 快手作品侵权永久封号能申诉吗第二次封多久 抖音账号永久封禁怎么办?申诉无效还能不能解封 抖音封号永久申诉内容怎么写? 被永久封号了如何解开 抖音永久封号是要申诉解封吗? 怎么键盘快速复制 手机防水怎么去弄?需要什么材料或者胶水之类的! 街上手机防水镀膜和膜结手机纳米防护有什么区别? 手机经过纳米防水涂层处理后,真的能防水吗 市面上手机防水是真的吗?和膜结手机纳米防护两者有什么区别? 手机防水镀膜是什么?膜结手机纳米防护和防水镀膜的区别是什么? 智能手机防水采用什么材料和加工工艺? 手机防水密封圈常用什么材质? 防水手机的扬声器是怎样防水的? 手机有没有防水的? Session是什么意思? 数据连接池的工作机制是什么? 美工区布局如何做到教育性和艺术性相统一 memcache原理是什么?是否能存入2m的value 如何创设美工区角活动 hibernate中持久太对象不能再次被保存? hibernate中持久太对象不能再次被保存? hashmap的最大容量是多少,在多少的时候会导致查询响应过慢 hashmap的最大容量是多少,在多少的时候会导致查询响应过慢 如何有效投放幼儿园美工区活动材料 幼儿园环境创设的基本要求有哪些 如何合理的进行小班美工区材料投放结题报告 1.美术活动材料的设置与投放是否要遵循幼儿能力水平的发展?以及考虑操作中的安全性?为什么? 幼儿园怎样开展好中班美工区域活动 VBA求解:行数未知,超10000行,想用VBA数组方式给对应的G列赋值,G列赋值 这个vba要怎么写 为什么每次香蕉买回来过一天就黑了?? 为什么香蕉放一两天就会变黑 香蕉熟了以后为什么它的皮变黑的速度那么快 香蕉放几天皮就变黑,这样还能吃吗?
  • 焦点

最新推荐

猜你喜欢

热门推荐