重写eques后重写hashCode必要性

1、首先我们看看对象默认的(Object)的equals方法和hashcode方法

public boolean equals(Object obj) {

return(this== obj);

}

public native int hashCode();

对象在不重写的情况下使用的是Object的equals方法和hashcode方法,从Object类的源码我们知道,默认的equals 判断的是两个对象的引用指向的是不是同一个对象;而hashcode也是根据对象地址生成一个整数数值;



2、重写equals

案例场景:

定义一个User对象有多个属性值姓名、年龄、身份证;

我们写代码的时候会发现,两个new出来的User()对象 无论他们的的各项值是否一样两个对象equals永远都是false,两个对象值完全一样放到HashSet里面它会把这两个值完全一样的对象当成两个不同的对象了,这样的话好像HashSet的特性就丢失了;

其实原因就是我们没有重写User的equals方法,它会调用Object的equals方法,就如上图一样,Object的equals方法是比较对象的引用对象是否是同一个,两个new出来的对象当然不一样。

好了现在需求来了,我们需要两个对象的各项属性值一样的就认为这两个对象是相等的;那么此时我们就需要重写equals方法了;

代码如下

public classUser {

privateStringname;//姓名

privateStringIdCard;//身份证

private intage;//年龄

/**

* 重写equals

*@paramobj

*@return

*/

@Override

@Override

public boolean equals(Object obj) {

if(obj  instanceof  User) {

User user = (User) obj;

if(user.getIdCard().equals(this.IdCard) && user.getName().equals(this.name) && user.getAge() ==this.age) {

return true;

}else{

return false;

}

}else{

return false;

}

}

//......省略N行代码

}

那么现在关键的地方来了:现在我们重写了User对象的equals方法,但并没有重写hashcode方法。

(1)首先测试下equals的正确性

User user1=newUser();

user1.setName("路西");

user1.setAge(18);

user1.setIdCard("430");

User user2=newUser();

user2.setName("路西");

user2.setAge(18);

user2.setIdCard("430");

System.out.println("user1.equals(user2)="+user1.equals(user2));

user1.equals(user2)测试结果为true;

(2)在两个对象equals的情况下进行把他们分别放入Map和Set中

在上面的代码基础上追加如下代码:

Set set =newHashSet();

set.add(user1);

set.add(user2);

Map map=newHashMap();

map.put(user1,"user1");

map.put(user2,"user2");

System.out.println("set 长度"+set.size());

System.out.println("map 长度"+map.keySet().size());;

测试打印结果为:


好了现在问题来了,明明user1和user2两个对象是equals的那么为什么把他们放到set中会有两个对象(Set特性是不允许重复数据的),还有Map也把两个同样的对象当成了不同的Key(Map的Key是不允许重复的,相同Key会覆盖);

(3)这里我先抛出结果,至于原理后面再进行描述

原因是user1和user2的hashcode 不一样导致的;



因为我们没有重写父类(Object)的hashcode方法,Object的hashcode方法会根据两个对象的地址生成对相应的hashcode;

user1和user2是分别new出来的,那么他们的地址肯定是不一样的,自然hashcode值也会不一样。

Set区别对象是不是唯一的标准是,两个对象hashcode是不是一样,再判定两个对象是否equals;

Map 是先根据Key值的hashcode分配和获取对象保存数组下标的,然后再根据equals区分唯一值(详见下面的map分析)


3、重写hashcode方法;

public classUser  {

privateStringname;//姓名

privateStringIdCard;//身份证

private intage;//年龄

* 重写equals

*@paramobj

*@return

*/

@Override

public boolean equals(Object obj) {

if(obj  instanceof  User) {

User user = (User) obj;

if(user.getIdCard().equals(this.IdCard) && user.getName().equals(this.name) && user.getAge() ==this.age) {

return true;

}else{

return false;

}

}else{

return false;

}

}

@Override

public int hashCode() {

intresult =name.hashCode();

result =31* result +IdCard.hashCode();

result =31* result +age;

returnresult;

}

//......省略N行代码

}

我们按之前的流程重新测试一遍结果:

User user1=newUser();

user1.setName("路西");

user1.setAge(18);

user1.setIdCard("430");

User user2=newUser();

user2.setName("路西");

user2.setAge(18);

user2.setIdCard("430");

System.out.println("user1.equals(user2)="+user1.equals(user2));

Set set =newHashSet();

set.add(user1);

set.add(user2);

Map map=newHashMap();

map.put(user1,"user1");

map.put(user2,"user2");

System.out.println("set 长度"+set.size());

System.out.println("map 长度"+map.keySet().size());;

System.out.println("user1的hashcode"+user1.hashCode());

System.out.println("user2的hashcode"+user2.hashCode());

打印结果:



4、补充HashMap知识

hashMap组成结构:hashMap是由数组和链表组成;

hashMap的存储:一个对象存储到hashMap中的位置是由其key 的hashcode值决定的;查hashMap查找key: 找key的时候hashMap会先根据key值的hashcode经过取余算法定位其所在数组的位置,再根据key的equals方法匹配相同key值获取对应相应的对象;

案例:

(1)hashmap存储

存值规则:把Key的hashCode 与HashMap的容量 取余得出该Key存储在数组所在位置的下标(源码定位Key存储在数组的哪个位置是以hashCode & (HashMap容量-1)算法得出)这里为方便理解使用此方式;

//为了演示方便定义一个容量大小为3的hashMap(其默认为16)

HashMap map=newHashMap(3);

map.put("a",1);    得到key 为“a” 的hashcode 值为97然后根据 该值和hashMap 容量取余97%3得到存储位到数组下标为1;

map.put("b",2);    得到key 为“b” 的hashcode 值为98,98%3到存储位到数组下标为2;

map.put("c",3);    得到key 为“c” 的hashcode 值为99,99%3到存储位到数组下标为0;

map.put("d",4);    得到key 为“d” 的hashcode 值为100,100%3到存储位到数组下标为1;

map.put("e",5);    得到key 为“e” 的hashcode 值为101,101%3到存储位到数组下标为2;

map.put("f",6);    得到key 为“f” 的hashcode 值为102,102%3到存储位到数组下标为0;



(2)hashmap的查找key

得到key在数组中的位置:根据上图,当我们获取key 为“a”的对象时,那么我们首先获得 key的hashcode97%3得到存储位到数组下标为1;

匹配得到对应key值对象:得到数组下表为1的数据“a”和“c”对象, 然后再根据 key.equals()来匹配获取对应key的数据对象;

hashcode 对于HashMapde:如果没有hashcode 就意味着HashMap存储的时候是没有规律可寻的,那么每当我们map.get()方法的时候,就要把map里面的对象一一拿出来进行equals匹配,这样效率是不是会超级慢;


5、hashcode方法文档说明

在equals方法没被修改的前提下,多次调用同一对象的hashcode方法返回的值必须是相同的整数;

如果两个对象互相equals,那么这两个对象的hashcode值必须相等;

为不同对象生成不同的hashcode可以提升哈希表的性能;

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,493评论 18 399
  • 实际上,HashSet 和 HashMap 之间有很多相似之处,对于 HashSet 而言,系统采用 Hash 算...
    曹振华阅读 2,505评论 1 37
  • java笔记第一天 == 和 equals ==比较的比较的是两个变量的值是否相等,对于引用型变量表示的是两个变量...
    jmychou阅读 1,471评论 0 3
  • 一、基本数据类型 注释 单行注释:// 区域注释:/* */ 文档注释:/** */ 数值 对于byte类型而言...
    龙猫小爷阅读 4,243评论 0 16
  • 谨以此文献给我们最美丽的十八岁。 大二。计科男。北方燥热的城市。日子过得像最蓝的天空,最白的云,波...
    相机信纸棋阅读 273评论 2 2