在Object中有两个重要的方法:hashCode()和equals(Object obj)方法,并且当你按ctrl+alt+s时会有Generator hashCode()和equals()。我们不禁会想这两个方法到底有什么用,让eclipse提供自动生成这两个方法的模板呢?

这两个方法主要是在hash的数据结构中。如HashSet<E> 、 HashMap<K,V>中。

内容提要:

下面的代码ElementWithoutHashAndEqual类中定义了字段、构造方法、把hashCode()和equals()方法注释掉。然后再HashTest这个类中进行测试,看看运行结果。然后你再把ElementWithoutHashAndEqual类中的hashCode()和equals()方法的注释去掉,你

再看看运行结果是什么。这时你就会发现hashCode()和equals()方法的重要性了。 接着再从源码的角度看看为什么需要些这两个方法.

//ElementWithoutHashAndEqual类的代码如下:

 package com.qls.hashAndEquals;

 public class ElementWithoutHashAndEqual {
private int age;
private String name; public ElementWithoutHashAndEqual(int age, String name) {
this.age = age;
this.name = name;
} /*@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
} @Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ElementWithoutHashAndEqual other = (ElementWithoutHashAndEqual) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}*/ public String toString() {
return "ElementWithoutHashAndEqual [age=" + age + ", name=" + name + "]";
}
public static void main(String[] args) {
// TODO Auto-generated method stub } }

//HashTest的代码如下:

 package com.qls.hashAndEquals;

 import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.HashSet; /**在HashSet<E>,HashMap<K,V>中的元素E和K,必须要重写hashCode()和equals方法。
* 在大多数情况下E 写成String,Integer
* 等java自带的类。其实这些类已经重写了Object类中hashCode()和equals方法。
* 所以你感觉不到hashCode()方法和equals()方法的重要性。
* 这里我们自定义一个类,看它不重写hashCode()和equals方法会有什么后果。
* @author 秦林森
*
*/
public class HashTest { public static void main(String[] args) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
// TODO Auto-generated method stub
/**
* 用HashSet做例子看HashSet<E>中的元素E类中不重写hashCode()方法,和equals(Object obj);方法
* 的效果:
* 下面HashSet的遍历结果为:
* ElementWithoutHashAndEqual [age=18, name=sixi]
ElementWithoutHashAndEqual [age=18, name=sixi]
ElementWithoutHashAndEqual [age=18, name=sixi]
咋看以下是不是感觉这违背了HashSet不能加重复元素的基本原则。
其实这并没有违背因为Object类中的equals方法是比较两个对象的地址的。
那么hashCode()为什么要重写呢?
再看一看HashMap做例子的情况吧!
*/
HashSet<ElementWithoutHashAndEqual> hashSet = new HashSet<ElementWithoutHashAndEqual>();
hashSet.add(new ElementWithoutHashAndEqual(18, "sixi"));
hashSet.add(new ElementWithoutHashAndEqual(18, "sixi"));
hashSet.add(new ElementWithoutHashAndEqual(18, "sixi"));
for(ElementWithoutHashAndEqual e2:hashSet){
System.out.println(e2);
}
/**
* HashMap做例子看看HashMap<K,V>中的元素K这个类不重写hashCode()和equals方法的严重性。
*/
HashMap<ElementWithoutHashAndEqual, Integer> hashMap=new HashMap<>();
//先用反射向HashMap中添加元素:
hashMap.put(ElementWithoutHashAndEqual.class
.getConstructor(new Class[]{int.class,String.class})
.newInstance(new Object[]{29,"ouyangfeng"})
, 1);
//我们再看看用get(K key)方法能不能把value取出来。
Integer value = hashMap.get(ElementWithoutHashAndEqual.class
.getConstructor(new Class[]{int.class,String.class})
.newInstance(new Object[]{29,"ouyangfeng"}));
System.out.println("value="+value);//输出结果为value=null,而不是value=1.
/**
* 直接new一个对象加在HashMap中。这时你就会看得非常明白了,我之所以用反射创建对象,
* 因为这种创建对象方式比较不容易看懂,从而迷惑你以为put(key,value) 和get(key)中的key是
* 同一个对象。
*/
hashMap.put(new ElementWithoutHashAndEqual(6, "AbrahamLincoln"), 3);
//下面语句的输出结果还为value=null.
System.out.println("value="+hashMap.get(new ElementWithoutHashAndEqual(6, "AbrahamLincoln")));
/**
* 但是当你把ElementWithoutHashAndEqual这个类中的hashCode()、equals()方法的注释取消时,
* 输出结果就会变为你所想要的结果了,结果如下:
* ElementWithoutHashAndEqual [age=18, name=sixi]
value=1
value=3
生成hasCode和equals方法如下:
ctr+alt+s---->Generate hashCode() and equals()。便可以生成这两个函数了。
下面将出源码中看为什么需要在HashSet<E> 和HashMap<K,V>中的E、 K需要这两个函数。
*/
} }

分析为什么需要hashCode()和equals()方法。分析如下:

首先讲在HashMap中如何根据key,得到value的。

第一步:int hash=hash(key)【这个函数调用了key类中的hashCode()函数】得到某个值,

第二步:根据函数int i=indexFor(hash,table.length);找到这个i值在数组table的值table[i],这个table[i]中的值就是Map.Entry<K,V>【其中Entry<K,V> 为Map中的一个静态类】

第三步:有可能多个对象产生的hashCode()值一样,所以在源码中进行了这样的遍历:

for (Entry<K,V> e = table[i]; e != null; e = e.next) {//这个遍历意思就是table[i]中所存放的值Entry<K,V>可能不止一个。用到了链表的数据结构,对各个节点进行遍历。
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k)))//对Entry<K,V>进行筛选,找到符合的Entry<K,V>,这个必然只有一个。

第四步:用Entry<K,V>中的getValue(),便可以取得value值了。上述步骤所用到的源码如下所示:

  final Entry<K,V> getEntry(Object key) {
if (size == 0) {
return null;
} int hash = (key == null) ? 0 : hash(key);
for (Entry<K,V> e = table[indexFor(hash, table.length)];
e != null;
e = e.next) {
Object k;
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
}
return null;
}
 public V get(Object key) {
if (key == null)
return getForNullKey();
Entry<K,V> entry = getEntry(key); return null == entry ? null : entry.getValue();
}

在HashSet 中其实它添加元素也用到了Map中的方法,源码如下所示:

public boolean add(E e) {
return map.put(e, PRESENT)==null;
}。

hashCode()方法和equals方法的重要性。的更多相关文章

  1. 为什么要重写hashCode()方法和equals()方法及如何重写

    我想写的问题有三个: 1.首先我们为什么需要重写hashCode()方法和equals()方法 2.在什么情况下需要重写hashCode()方法和equals()方法 3.如何重写这两个方法 **** ...

  2. java 集合 HashSet 实现随机双色球 HashSet addAll() 实现去重后合并 HashSet对象去重 复写 HashCode()方法和equals方法 ArrayList去重

    package com.swift.lianxi; import java.util.HashSet; import java.util.Random; /*训练知识点:HashSet 训练描述 双色 ...

  3. 为什么要重写hashcode方法和equals方法

    我们可能经常听到说重写equals方法必须重写hashcode方法,这是为什么呢?java中所有的类都是Object的子类,直接上object源码 /* * Copyright (c) 1994, 2 ...

  4. Java 重写hashCode 方法和equals方法

    package Container; import java.util.HashSet; import java.util.Iterator; /* Set 元素是无序的(存入和取出的顺序不一定一致) ...

  5. hashCode方法和equals方法比较

    为什么用HashCode比较比用equals方法比较要快呢?我们要想比较hashCode与equals的性能,得先了解HashCode是什么. HashCode HashCode是jdk根据对象的地址 ...

  6. 集合hashCode()方法和equals()办法

    1.哈希码:         Object中的HashCode方法会返回该对象的的内存真实地址的整数化表示,这个形象的不是真正抵制的整数值就是哈希码. 2.利用哈希码向集合中插入数据的顺序?     ...

  7. hashCode()方法和equal()方法的区别

    本文参考地址:http://www.cnblogs.com/zgq0/p/9000801.html hashCode()方法和equal()方法的作用其实一样,在Java里都是用来对比两个对象是否相等 ...

  8. java数组、java.lang.String、java.util.Arrays、java.lang.Object的toString()方法和equals()方法详解

    public class Test { public static void main(String[] args) { int[] a = {1, 2, 4, 6}; int[] b = a; in ...

  9. Object、String、数组的 toString() 方法和 equals() 方法及java.util.Arrays

    public class Test { public static void main(String[] args) { int[] a = {1, 2, 4, 6}; int[] b = a; in ...

随机推荐

  1. IDEA的使用方法(二)(代码提示)

    工欲善其事必先利其器: 在eclipse用久了代码提示对自己纯手搓代码还是不太好的,我就算是死,从楼上跳下去,也不会从了IDEA的代码提示的,在手搓了一个hello world之后,我写的是JAVA? ...

  2. JQuery制作网页—— 第二章 JavaScript操作BOM对象

    1.window对象: 浏览器对象模型(BOM)是javascript的组成之一, 它提供了独立与浏览器窗口进行交换的对象,使用浏览器对象模型可以实现与HTML的交互. 它的作用是将相关的元素组织包装 ...

  3. 【shopex】添加网页挂件widgets

    一步步做个widgets 基础篇 首先建立一个目录plugins/widgets/helloword 这个就是新的挂件目录,系统的每个widgets都是一个目录 里面放两个文件: widgets.ph ...

  4. 解决cmd 运行python socket怎么终止运行

    在cmd里启动python写了一个socket服务端的程序,但是启动之后由于监听连接的是一个死循环 这时想终止运行,发现按ctrl+c,ctrl+z,ctrl+d都不能终止 用ctrl+break解决

  5. P2158 [SDOI2008] (欧拉函数

    题目描述 作为体育委员,C君负责这次运动会仪仗队的训练.仪仗队是由学生组成的N * N的方阵,为了保证队伍在行进中整齐划一,C君会跟在仪仗队的左后方,根据其视线所及的学生人数来判断队伍是否整齐(如下图 ...

  6. 003---wsgi和wsgiref模块

    WSGI: 全称:Web Server Gatway Interface ,web服务网关接口,独立的,与django无关,他们俩只是遵循一个约定,是一个协议. wsgiref模块: 实现了WSGI协 ...

  7. 笔记-HTTP及HTTPS

    笔记-HTTP及HTTPS 1.      HTTP 1.1.    简介 HTTP:hyper text transfer protocol 超文本传输协议 http常用请求方式,method ge ...

  8. spark练习---ip匹配以及广播的特性

    今天,我们还是在介绍spark的小练习,这次的小练习还是基于IP相关的操作,我们可以先看一下今天的需求,我们有两个文件, 第一个文件,是IP的字典,也就是我们上一篇介绍过的,就是表明了所有IP字段所属 ...

  9. Python 外部函数调用库ctypes简介

    Table of Contents 1. 参考资料 2. ctypes简介 2.1. 数据类型 2.2. 调用.so/.dll 2.2.1. 加载动态链接库 2.2.2. 调用加载的函数 2.2.3. ...

  10. HDU 4576 Robot(概率dp)

    Robot Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 102400/102400 K (Java/Others)Total Sub ...