java中“”==“” equals hashcode的关系
ava中的数据类型,可分为两类:
1.基本数据类型,也称原始数据类型。byte,short,char,int,long,float,double,boolean
他们之间的比较,应用双等号(==),比较的是他们的值。
2.复合数据类型(类)
当他们用(==)进行比较的时候,比较的是他们在内存中的存放地址,所以,除非是同一个new出来的对象,他们的比较后的结果为true,否则比较后结果为false。 JAVA当中所有的类都是继承于Object这个基类的,在Object中的基类中定义了一个equals的方法,这个方法的初始行为是比较对象的内存地 址,但在一些类库当中这个方法被覆盖掉了,如String,Integer,Date在这些类当中equals有其自身的实现,而不再是比较类在堆内存中的存放地址了。
对于复合数据类型之间进行equals比较,在没有覆写equals方法的情况下,他们之间的比较还是基于他们在内存中的存放位置的地址值的,因为Object的equals方法也是用双等号(==)进行比较的,所以比较后的结果跟双等号(==)的结果相同。
public boolean equals(Object obj) { return (this == obj); }
如果对象没有覆写equals方法默认使用Object方法,就是比较对象的内存地址是否一样。
若某个类没有覆盖equals()方法,当它的通过equals()比较两个对象时,实际上是比较两个对象是不是同一个对象。这时,等价于通过“==”去比较这两个对象
注意点:
如果类没有重写equals,那么对于该类的对象来说“==”和“equals”没有区别。都是比较对象的内存地址。 但在一些类库当中这个方法被覆盖掉了,如String,Integer,Date在这些类当中equals有其自身的实现,而不再是比较类在堆内存中的存放地址了。所以会有很多经典的面试题:
String a = new String ("abc");
String b = new String ("abc");
System.out.println(a.equals(b));
System.out.println(a==b);
返回值是true和false
String以及基本数据类型的包装类中都重写了hashCode()方法,他们生成的哈希码是跟他们的内容
(这里就是指值)息息相关,也就是说在用equals()比较两个变量是否相等的时候只要他们的值相等,那么就返回true
第二:我们可以覆写覆盖equals()方法。则通过equals()比较该类的两个对象是否相等,但是需要注意的一点如果你重写equals()方法,那么你必须重写hashCode()方法
从开始学习Java,哈希码以及equals和==的区别就一直困扰着我。
要想明白equals和==的区别首先应该了解什么是哈希码,因为在jdk的类库中不管是object实现的equals()方法还是String重写的equals()方法以及
其它基本数据类型的包装类重写的euqals()方法,他们在比较对象的时候都是根据hashCode()方法返回的哈希码来判断两个对象是否相等的,所以要想搞清楚
equals()就必须要知道什么是哈希码。
那么究竟是什么哈希码呢?哈希码是可以根据的自己的需求,采用不同的算法产生的一个Int型数字。Object的hashCode()方法返回的哈希码是根据对
象的内存地址来生成的,所以每个对象的哈希码是不相同的,如果你要比较的两个变量的类型没有重写Object的hashCode()方法那么这两个变量除非是指向
相同的对象(地址相同),否则返回的一定是false。而String以及基本数据类型的包装类中都重写了hashCode()方法,他们生成的哈希码是跟他们的内容
(这里就是指值)息息相关,也就是说在用equals()比较两个变量是否相等的时候只要他们的值相等,那么就返回true,因为他们生成的哈希码相等。有个
值得注意的地方是:在JDK的类中只要重写的Object的equals()方法,那就肯定重写了它的hashCode()方法,因为equals()方法中在比较两个变量时,
判断的标准就是哈希码是否一样,Object中的hashCode()方法是根据对象的内存地址生成的,如果重写了equals()方法而继续使用原来的hashCode()方
法生成的哈希码作为判断相等的依据,那显然达不到我们要改变判断对象是否相等的标准的效果。
既然知道了什么是哈希码,现在就可以说明equals()和==的区别了,对于没用重写Object的equals()方法的类型所生成的对象的比较,equals()
和==是效果一样的,==比较的是两个变量所指向的对象在内存中指向的地址是否一样,而当两个变量的类型中继承了Object的equals()方法的时候,由于
该方法比较的标准是看哈希码是否相等,而哈希码是由hashCode()方法生成的,该方法生成哈希码的依据是对象在内存中的地址,最终比较的还是地址。所
以说equals()和==效果一样。而对于像String和那些基本数据类型的包装类来说equals()和==就不一样了,因为他们重写了Object的equals()方法和
hashCode()方法,使得equals()方法的判断标准发生了改变,他们的判断标准是看对象的内容是否相等,这里就是指值是不是一样,因为他们的哈希码是
根据对象的值生成的,与内存地址无关了,所以他们的equals()方法比较的是对象的值是否相等,而==比较的仍然是地址。所以equals()和==就不一样了。
这里还要注意一下,在比较值的时候,一般==比较的是基本数据类型,而equals()比较的是引用数据类型,地址相同一定值相等,而值相等地址不一定
相同。如果比较的是地址,那最好是用==,因为无论是否重写了Object的equals()方法,==永远比较的是地址,equals()比较的是哈希码,而哈希码生成
的标准是由类作者自己根据需求来控制的。
结论2:
如果两个对象x和y满足x.equals(y) == true,它们的哈希码(hash code)应当相同。Java对于eqauls方法和hashCode方法是这样规定的:(1)如果两个对象相同(equals方法返回true),那么它们的hashCode值一定要相同;(2)如果两个对象的hashCode相同,它们并不一定相同
1、如果两个对象相等,那么它们的hashCode()值一定相同。
这里的相等是指,通过equals()比较两个对象时返回true。
2.、如果两个对象hashCode()相等,它们并不一定相等。
因为在散列表中,hashCode()相等,即两个键值对的哈希值相等。然而哈希值相等,并不一定能得出键值对相等。补充说一句:“两个不同的键值对,哈希值相等”,这就是哈希冲突。
我们来看下面的例子
HashSet (需要重写hashCode和equals方法)
一般描述的事物需要往集合中添加,那么都需要重写这两个方法
删除和判断元素是否存在,都是先判断hashCode 看看是否存在,若存在则继续equals();

import java.util.*;
class Person
{
private String name;
private int age;
Person(String name,int age)
{
this.name=name;
this.age=age;
}
public int hashCode()//重写
{
return name.hashCode()+age ;
}
public boolean equals(Object obj)//重写 Object不能换
{
if(!(obj instanceof Person))
return false;
Person p=(Person)obj; System.out.println(this.name+"...."+p.name); return this.name.equals(p.name)&&this.age==p.age;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
}
class HashSetDemo
{
public static void main(String[] args)
{
HashSet hs=new HashSet(); hs.add(new Person("lisi01",30));
hs.add(new Person("lisi02",33));
hs.add(new Person("lisi03",35));
hs.add(new Person("lisi02",33));
hs.add(new Person("lisi01",30));
hs.add(new Person("lisi04",32));
hs.add(new Person("lisi03",35)); Iterator it=hs.iterator(); while(it.hasNext())
{
Person p=(Person)it.next();;
sop(p.getName()+" "+p.getAge());
}
}
public static void sop(Object obj)
{
System.out.println(obj); }
}
参考案例2:
第一:
Set集合没有顺序,也不允许重复。
为什么要这样:模拟现实的集合。
这里的重复只是:对象的重复
何为对象的重复:指的就是同一个对象。
何为同一个对象:内存中,所在的内存编号一致。
内存编号的表示是什么:哈希码(哈希码一般是 类名 和 对象所在内存地址的十六进制数字表示 的组合)。
第二:
这种设置和实现中的矛盾在什么地方:
现实生活中只要属性相同,我们就认为那是同一个对象。
这与计算机比较同一个对象的方法不同(计算机使用内存地址,即哈希码)
于是,就需要重写equals方法和hashCode方法(&&)来让程序的运行结果符合现实生活
基本数据类型的实现类都已经重写了上面的两个方法。
第三:
为什么要重写equals方法和hashCode方法(技术实现原理):
程序向HashSet中添加一个对象时,先用hashCode方法计算出该对象的哈希码。
比较:
(1),如果该对象哈希码与集合已存在对象的哈希码不一致,则该对象没有与其他对象重复,添加到集合中!
(2),如果存在于该对象相同的哈希码,那么通过equals方法判断两个哈希码相同的对象是否为同一对象(判断的标准是:属性是否相同)
1>,相同对象,不添加。
2>,不同对象,添加!
这时有两个疑问:
1,为什么哈希码相同了还有可能是不同对象?
2,为什么经过比较哈希码还需要借助equals方法判断?
答:
首先:
按照Object类的hashCode方法,是不可能返回两个相同的哈希码的。(哈希码唯一标志了对象)
然后:
Object类的hashCode方法返回的哈希码具有唯一性(地址唯一性),但是这样不能让程序的运行逻辑符合现实生活。(这个逻辑就是:属性相同的对象被看作同一个对象。)
为了让程序的运行逻辑符合现实生活,Object的子类重写了hashCode的方法(基本数据类型的实现类都已经重写了两个方法,自定义的类要软件工程 师自己重写。)
那么:
重写的宗旨是什么?
重写就是为了实现这样的目的:属性相同的不同对象在调用其hashCode方法后,返回的是同样的哈希码。
但是
我们在重写的时候,发现几乎所有的写法都无法避免一个bug:有一些属性不同的对象(当然是不同的对象),会返回相同的哈希码。(即 重码)
最后:
为了解决这个问题:在哈希码相同的时候,再用equals方法比较两个对象的对应属性是否相同,这样,确保了万无一失。
这样:上面两个问题得到解决。
5
下面给出一个属性不同但哈希码相同的例子:
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
class Person {
private String name;
private int id;
Person(String name,int id) {
this.name = name;
this.id = id;
}
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
public void setId(int id){
this.id = id;
}
public int getId(){
return id;
}
public int hashCode(){
return name.hashCode()+id; //使用字符串哈希值与Integer的哈希值的组合
//这样会产生重码,实际上重码率很高
}
public boolean equals(Object obj){
if(obj instanceof Person){ //
Person p = (Person)obj;
return(name.equals(p.name) && id == p.id);
}
return super.equals(obj);
}
}
public class TestHashSet2 {
public static void main(String[] args) {
Person p1 = new Person("a",1);
Person p2 = new Person("b",0);
Set<Person> set = new HashSet<Person>();
set.add(p1);
set.add(p2);
Iterator<Person> it = set.iterator();
while(it.hasNext()){
System.out.println(it.next().getName());
}
}
}
- 总思路:hashCode不同时,则必为不同对象。hashCode相同时,根据equlas()方法判断是否为同一对象。
- 在HashSet,HashMap,HashTable中都存在该问题。
java中“”==“” equals hashcode的关系的更多相关文章
- 浅谈Java中的hashcode方法以及equals方法
哈希表这个数据结构想必大多数人都不陌生,而且在很多地方都会利用到hash表来提高查找效率.在Java的Object类中有一个方法: public native int hashCode(); 根据这个 ...
- K:java中的hashCode和equals方法
hashCode和equals方法是Object类的相关方法,而所有的类都是直接或间接的继承于Object类而存在的,为此,所有的类中都存在着hashCode和equals.通过翻看Object类 ...
- 关于java中的hashcode和equals方法原理
关于java中的hashcode和equals方法原理 1.介绍 java编程思想和很多资料都会对自定义javabean要求必须重写hashcode和equals方法,但并没有清晰给出为何重写此两个方 ...
- java中equals和hashCode方法随笔二
前几天看了篇关于java中equals和hashCode方法的解析 1.Object类中的equals方法和hashCode方法. Object类中的equals和hashCode方法简单明了,所有的 ...
- Java中equals和hashcode的区别?
Java中equals和hashcode方法是在Object对象中的,所以每个对象都有这两个方法,大多数时候我们为了实现特定需求需要重写这两个方法 equals和hashcode方法常用在同一个类中用 ...
- java中equals和==的区别 (转)
java中equals和==的区别 值类型是存储在内存中的堆栈(以后简称栈),而引用类型的变量在栈中仅仅是存储引用类型变量的地址,而其本身则存储在堆中. ==操作比较的是两个变量的值是否相等,对于引 ...
- 浅谈Java中的hashcode方法
哈希表这个数据结构想必大多数人都不陌生,而且在很多地方都会利用到hash表来提高查找效率.在Java的Object类中有一个方法: 1 public native int hashCode(); 根据 ...
- java中的hashcode
hashcode的作用 对于包含容器类型的程序设计语言来说,基本上都会涉及到hashCode.在Java中也一样,hashCode方法的主要作用是为了配合基于散列的集合一起正常运行,这样的散列集合包括 ...
- 【转】浅谈Java中的hashcode方法(这个demo可以多看看)
浅谈Java中的hashcode方法 哈希表这个数据结构想必大多数人都不陌生,而且在很多地方都会利用到hash表来提高查找效率.在Java的Object类中有一个方法: public native i ...
随机推荐
- [验证码识别技术] 字符型验证码终结者-CNN+BLSTM+CTC
验证码识别(少样本,高精度)项目地址:https://github.com/kerlomz/captcha_trainer 1. 前言 本项目适用于Python3.6,GPU>=NVIDIA G ...
- jchdl - GSL实例 - Mul(无符号数的乘法)
这里实现最原始的阵列乘法,逐位相乘然后加到一起. 参考链接 https://github.com/wjcdx/jchdl/blob/edcc3e098d4f1cb21677e86e87a114 ...
- 我一个二本大学是如何拿到阿里offer的
作者:薛勤,互联网从业者,编程爱好者. 本文首发自公众号:代码艺术(ID:onblog)未经许可,不可转载 01:终于步入大学 我既没有跨过山和大海,也没有穿过人山人海,我就是我,一个普通本科大学生. ...
- Java实现 LeetCode 139 单词拆分
139. 单词拆分 给定一个非空字符串 s 和一个包含非空单词列表的字典 wordDict,判定 s 是否可以被空格拆分为一个或多个在字典中出现的单词. 说明: 拆分时可以重复使用字典中的单词. 你可 ...
- Java实现旅行商问题
1 问题描述 何为旅行商问题?按照非专业的说法,这个问题要求找出一条n个给定的城市间的最短路径,使我们在回到触发的城市之前,对每个城市都只访问一次.这样该问题就可以表述为求一个图的最短哈密顿回路的问题 ...
- java实现第五届蓝桥杯猜字母
猜字母 题目描述 把abcd-s共19个字母组成的序列重复拼接106次,得到长度为2014的串. 接下来删除第1个字母(即开头的字母a),以及第3个,第5个等所有奇数位置的字母. 得到的新串再进行删除 ...
- 【asp.net core 系列】4. 更高更强的路由
0. 前言 在之前我们介绍了请求通过路由寻找到控制器,以及控制器与视图的数据流转.那么,我们回过头来,再看看路由的一些其他用法. 1. 路由属性(Route Attribute) 按照英文的直接翻译, ...
- java启动RabbitMQ消息报异常解决办法
启动SpringCloud微服务,RabbitMQ报如下异常: 2019-08-12 18:15:49.543 ERROR 53096 --- [68.252.131:5672] o.s.a.r.c. ...
- [bx] and loop
1.[bx] 表示一个内存单元,它的偏移地址在bx中 mov al,[bx] 2.描述符号() 来表示一个寄存器或一个内存单元中的内容. 约定符号idata表示常量. 3.loop 标号 CPU在执行 ...
- Scrapy 小技巧(一):使用 scrapy 自带的函数(follow & follow_all)优雅的生成下一个请求
前言 如何优雅的获取同一个网站上下一次爬取的链接并放到生成一个 Scrapy Response 呢? 样例 from urllib import parse import scrapy class S ...