好吧好吧,我承认这有点标题党的嫌疑,我这不是隔太久没更新,有点兴奋么。
板砖拍够了,臭鸡蛋扔够了,别来打酱油便行了。我这就进入正题。其实正确的标题应该叫Effective Java读书心得之鸡翅的故事。
关于鸡翅的故事,相传最近最近以前……
1
import
static
org.junit.Assert.
*
;
2
3
import
java.util.HashMap;
4
5
import
org.junit.Test;
6
7
8
public
class
TestObjectHashCode {
9
10
@Test
11
public
void
testIt(){
12
//
最近,麦当当推出了麦香翅,味道不是一般的好,那是相当的好。
13
//
于是受到消费者的青睐,大受欢迎。
14
鸡翅 麦香翅
=
new
鸡翅(
"
麦香翅
"
);
15
味道 味道好极了
=
new
味道(
"
味道好极了
"
);
16
HashMap 市场
=
new
HashMap();
17
市场.put(麦香翅, 味道好极了);
18
19
//
这一切都被一个山寨小食店看在眼里,他们决定打着麦香翅的名号,推出实际上味道一般的山寨麦香翅
20
鸡翅 山寨麦香翅
=
new
鸡翅(
"
麦香翅
"
);
21
22
//
山寨小食店的师傅还是很有智慧的,他们通过某某方式,通过ISO叉叉叉叉的认证。
23
//
他们很天真地认为他们的山寨翅可以媲美麦香翅。
24
assertTrue(山寨麦香翅.equals(麦香翅));
25
26
//
但是结果大家都知道了,山寨翅并没有获得市场的认可,鱼目混珠终究被市场识别出来。
27
assertFalse(味道好极了.equals(市场.get(山寨麦香翅)));
28
29
//
山寨小食店苦思瞑想,终于发现了问题,原来他们指打相同的名号是不行的。
30
//
他们的并没有山寨出麦香翅代号为HashCode的秘制酱料
31
assertFalse(麦香翅.hashCode()
==
山寨麦香翅.hashCode());
32
}
33
34
public
static
final
class
味道{
35
private
String description;
36
37
public
味道(String des){
38
description
=
des;
39
}
40
41
public
String getDescription() {
42
return
description;
43
}
44
45
public
void
setDescription(String aDes) {
46
this
.description
=
aDes;
47
}
48
49
}
50
51
public
static
final
class
鸡翅 {
52
53
private
String Name;
54
55
public
鸡翅(String name){
56
this
.Name
=
name;
57
}
58
59
public
String getName() {
60
return
Name;
61
}
62
63
public
void
setName(String aName) {
64
this
.Name
=
aName;
65
}
66
67
@Override
68
public
boolean
equals(Object obj){
69
if
(
!
(obj
instanceof
鸡翅)){
70
return
false
;
71
}
72
return
((鸡翅)obj).getName().equals(
this
.Name);
73
}
74
}
75
76
}
77
看完了不知道我想说啥?看来没认真看《Effective Java》嘛,这本书可是每个java程序员进阶必修之书,没看过真不能自称大虾级别。好了,这里说到了正题的正题,其实我想说的是:
《Effective Java》第八条:改写equals时总是要改写hashCode。
*为什么要改写hashCode
答:(书上原话)“如果不这样做的话,就会违反Object.hashCode的通用约定,从而导致该类无法与所有基于散列值(hash)的集合类在一起正常工作,这样的集合类包括HashMap,HashSet和Hashtable.
*那么为什么会导致该类无法与所有基于散列值(hash)的集合类在一起正常工作呢?
答:且看一个HashMap的源代码解释。
HashMap是通过一个叫table[]的数组来存取,table的每个元素是一个链表结构,链表的每个元素称为 Entry<key,value>,是真正存放key和value的对象。在put的过程中,HashMap会通过特定的哈希算法将key对象的hashCode对应到table的某个索引下,然后再用key对比链表中每个Entry.key,如果key相同则更新value。否则就加入新的 Entry到链表中。
<meta name="ProgId" content="Word.Document">
<meta name="Generator" content="Microsoft Word 11">
<meta name="Originator" content="Microsoft Word 11">
<link rel="File-List" href="file:///C:%5CDOCUME%7E1%5CADMINI%7E1%5CLOCALS%7E1%5CTemp%5Cmsohtml1%5C01%5Cclip_filelist.xml">
HashMap
的数据结构图:
再看一段HashMap的源代码:
1
public
V put(K key, V value) {
2
K k
=
maskNull(key);
//
如果key为null则使用缺省的Object
3
int
hash
=
hash(k);
//
将k的hashCode经过一定的计算得到新的HashCode
4
int
i
=
indexFor(hash, table.length);
//
取得HashCode在table中的位置
5
6
//
首先在数组内根据key的HashCode找到Entry链表的第一个Entry
7
for
(Entry
<
K,V
>
e
=
table[i]; e
!=
null
; e
=
e.next) {
8
//
如果Entry的key值HashCode相同,而且具有相同的引用或逻辑相等(equals)
9
if
(e.hash
==
hash
&&
eq(k, e.key)) {
10
//
将新的value放入Entry中,返回旧的value
11
V oldValue
=
e.value;
12
e.value
=
value;
13
e.recordAccess(
this
);
14
return
oldValue;
15
}
16
}
17
18
//
修改次数加1
19
modCount
++
;
20
//
在table的第i个位置的链表后加上一个新的Entry
21
addEntry(hash, k, value, i);
22
return
null
;
23
}
24
25
static
boolean
eq(Object x, Object y) {
26
return
x
==
y
||
x.equals(y);
27
}
28
*最后来看java.lang.Object的约定(经过自己语言描述,原话自己看书去)
1.如果一个类的equals方法所用到的信息(逻辑相等的条件因素)没有被修改的话,那么它hashCode也不会改变。换个角度来看,也就是说,hashCode返回值最好与equals方法所用到的信息相关。
2.如果两个实例根据equals对比是相等的,那么它们的HashCode相等。
3.如果两个实例根据equals对比是不相等的,那么它们的HashCode最好是不等,这对于Hash性能的提高有好处。
E.g 如果Person实例的ID属性没有被修改的话,那么它的HashCode也不会改变
1
public
class
Person{
2
private
String ID;
3
public
boolean
equals(Object obj){
4
if
(
!
(obj
instanceof
Person)
&&
((Person)obj).getID()
!=
null
){
5
return
false
;
6
}
7
return
((Person)obj).getID().equals(
this
.ID);
8
}
9
10
public
int
hashCode(){
11
if
(ID
==
null
){
12
return
23
;
13
}
else
{
14
return
ID.hashCode();
15
}
16
}
17
public
String getID() {
18
return
ID;
19
}
20
public
void
setID(String id) {
21
ID
=
id;
22
}
23
24
}
25
分享到:
相关推荐
《Java版大话西游源码》是一款基于Java编程语言开发的角色扮演游戏(RPG)教程,对于初学者和想要深入理解游戏开发的程序员来说,它提供了丰富的学习资源。这款教程涵盖了多线程技术和自动寻路算法等核心概念,是...
本文《OpenFaaS实战之五:大话watchdog》重点讨论了OpenFaaS的关键组件watchdog的原理和应用。 在OpenFaaS中,当外部请求到达API Gateway时,它会将请求转发到faas-netes组件。faas-netes作为服务提供者,不仅支持...
大话核心网.mobi
大话Java:从零基础到数据库、Web开发为所有打算深入掌握Java编程的读者编写,适用于初中级程序开发者,没有接触过Java语言的入门者也可以轻松地阅读《大话Java:从零基础到数据库、Web开发》。
《大话存储终极版》是IT领域内一本深受读者喜爱的存储技术图书,作者冬瓜哥(张冬)以其通俗易懂的语言,深入浅出地介绍了存储领域的诸多知识。这本书对于初学者来说是一份非常宝贵的资源,可以帮助他们快速入门并...
标题中的“框架封装1.0版本 大话C#之实践场景入门进阶必知点a,深入浅出解析教程”表明这是一个关于C#编程语言的教程,特别关注于实践场景的应用,适合初学者和进阶者。这个教程可能包含了对C#基础的巩固以及高级...
Java代码加速器 Java代码积累:并发 设计模式 数据结构 使用容器 实用 类 基础知识 并发性 演示线程的生命周期 生产者-消费者 设计模式参考《大话设计模式》 工厂简单模式 创造型模式 工厂方法模式 抽象工厂模式 ...
该项目是一个基于《大话设计模式》的Java设计模式学习源码实战,包含41个文件,其中36个为Java源文件,4个为Markdown文档,以及1个LICENSE文件。通过实际编码实践,帮助开发者深入理解并掌握设计模式的应用。
《大话JAVA性能优化》这份文档深入探讨了Java程序在多个层面的性能调优策略,旨在帮助开发者提高程序运行效率,降低资源消耗,提升用户体验。以下是对这些知识点的详细阐述: 1. **代码层次优化**:在代码编写阶段...
《深入浅出Spring Boot2》《图解Java多线程设计模式》 《深入理解Java虚拟机:JVM高级特性与最佳实践》 《深入理解计算机系统(原书第三版》《Netty权威指南 第2版》 《Netty 4核心原理与手写RPC框架实战》 ...
Android之大话设计模式——:抽象工厂模式借鉴.pdf
通读《大话Java性能优化》后,读者可以深入了解Java性能调优的许多主题及相关的综合性知识。读者也可以把《大话Java性能优化》作为参考,对于感兴趣的主题,直接跳到相应章节寻找答案。 总的来说,性能调优在很大...
总的来说,通过《大话数据分析:Tableau数据可视化实战》的数据集,学习者可以深入实践如何加载数据、构建视图、创建交互式仪表板,并用Tableau来解答业务问题。这涵盖了从数据导入、数据探索、可视化设计到故事呈现...
《大话java性能优化》是周明耀先生的一本深入探讨Java性能调优的专业书籍,其主要内容涵盖了Java程序设计中的各种性能优化策略和技术。这本书旨在帮助开发者理解和掌握如何提升Java应用的运行效率,减少资源消耗,...
大话java性能优化,大家可以搜一下这本书。这个是完美中文版,建议下载
Android之大话设计模式——:抽象工厂模式参考.pdf
本书 主要 提供 Java 性能 调 优 方面 的 参考 建议 及 经验交流。 作者 力求 做到 知识 的 综合 传播, 而 不是 仅仅 只 针对 Java 虚拟 机 调 优 进行 讲解, 另外 力求 每一 章节 都有 实际 的 案例 支撑。 具体 ...
大话java性能优化,pdf版!