`

hashCode的作用(转)

阅读更多

1.hashcode是用来查找的,如果你学过数据结构就应该知道,在查找和排序这一章有
例如内存中有这样的位置
0 1 2 3 4 5 6 7
而我有个类,这个类有个字段叫ID,我要把这个类存放在以上8个位置之一,如果不用hashcode而任意存放,那么当查找时就需要到这八个位置里挨个去找,或者用二分法一类的算法。
但如果用hashcode那就会使效率提高很多。
我 们这个类中有个字段叫ID,那么我们就定义我们的hashcode为ID%8,然后把我们的类存放在取得得余数那个位置。比如我们的ID为9,9除8的余 数为1,那么我们就把该类存在1这个位置,如果ID是13,求得的余数是5,那么我们就把该类放在5这个位置。这样,以后在查找该类时就可以通过ID除8 求余数直接找到存放的位置了。

2.但是如果两个类有相同的hashcode怎么办那(我们假设上面的类的ID不是唯一的),例如9除以8和17除以8的余数都是1,那么这是不是合法的,回答是:可以这样。那么如何判断呢?在这个时候就需要定义 equals了。
也就是说,我们先通过 hashcode来判断两个类是否存放某个桶里,但这个桶里可能有很多类,那么我们就需要再通过 equals 来在这个桶里找到我们要的类。
那么。重写了equals(),为什么还要重写hashCode()呢?
想想,你要在一个桶里找东西,你必须先要找到这个桶啊,你不通过重写hashcode()来找到桶,光重写equals()有什么用啊
3。你要对A类排序,有两种方法,一种就是让A类实现comparabole结构并实现compareTo()方法,那么可以通过Collections.sort(List <A> list)对其进行排序
另一种方法:自己定义一个类B实现Comparator类并实现compare方法,
然后通过Collections.sort(List <A> list,B b)进行排序

hashCode() 是用来产生哈希玛的,而哈希玛是用来在散列存储结构中确定对象的存储地址的,(这一段在 Java编程思想 中讲的很清楚的)象util包中的 带 hash 的集合类都是用这种存储结构 :HashMap,HashSet, 他们在将对象存储时(严格说是对象引用),需要确定他们的地址吧, 而HashCode()就是这个用途的,一般都需要重新定义它的,因为默认情况下,由 Object 类定义的 hashCode 方法会针对不同的对象返回不同的整数,这一般是通过将该对象的内部地址转换成一个整数来实现的,现在举个例子来说, 就拿HashSet来说 ,在将对象存入其中时,通过被存入对象的 hashCode() 来确定对象在 HashSet 中的存储地址,通过equals()来确定存入的对象是否重复,hashCode() ,equals()都需要自己重新定义,因为hashCode()默认前面已经说啦,而equals() 默认是比较的对象引用,你现在想一下,如果你不定义equals()的话,那么同一个类产生的两个内容完全相同的对象都可以存入Set,因为他们是通过 equals()来确定的,这样就使得HashSet 失去了他的意义,看一下下面这个: 

import java.util.HashSet;

public class TestHashSet {
	public static void main(String[] args) {

		HashSet set = new HashSet();
		for (int i = 0; i < 3; i++) {
			set.add(new Demo(i, i));
		}

		System.out.println(set);
		set.add(new Demo(1, 1));
		System.out.println(set);
		System.out.println(set.contains(new Demo(0, 0)));
		System.out.println(set.add(new Demo(1, 1)));
		System.out.println(set.add(new Demo(4, 4)));
		System.out.println(set);

	}

	private static class Demo {
		private int id;

		private int value;

		public Demo(int id, int value) {
			this.id = id;
			this.value = value;
		}

		// 重写toString方法
		public String toString() {
			return "value=" + value;
		}

		// 重写equals方法
		public boolean equals(Object o) {
			Demo a = (Demo) o;
			return (a.value == value) ? true : false;
		}

		// 重写hashCode方法
		public int hashCode() {
			return id;
		}
	}
}

 

分别注释掉hashCode()和 equals()来比较一下他们作用就可以拉,关键要自己动手看看比较的结果就可以记得很清楚啦

总结
hashCode() 方法使用来提高Map里面的搜索效率的,Map会根据不同的hashCode()来放在不同的桶里面,Map在搜索一个对象的时候先通过 hashCode()找到相应的桶,然后再根据equals()方法找到相应的对象.要正确的实现Map里面查找元素必须满足一下两个条件:
(1)当obj1.equals(obj2)为true时obj1.hashCode() == obj2.hashCode()必须为true
(2)当obj1.hashCode() == obj2.hashCode()为false时obj.equals(obj2)必须为false

Java中的集合(Collection)有两类,一类是List,再有一类是Set。你知道它们的区别吗?前者集合内的元素是有序的,元素可以重复;后者元素无序,但元素不可重复。(有序指的是存储顺序和添加顺序是相同的,并且可通过它的下标进行访问。而无序则刚好相反,它存储顺序和添加顺序无关,它是没有下标的)
那么这里就有一个比较严重的问题了:要想保证元素不重复,可两个元素是否重复应该依据什么来判断呢?这就是Object.equals方法了。
但是,如果每增加一个元素就检查一次,那么当元素很多时,后添加到集合中的元素比较的次数就非常多了。
也就是说,如果集合中现在已经有1000个元素,那么第1001个元素加入集合时,它就要调用1000次equals方法。这显然会大大降低效率。
哈 希算法也称为散列算法,是将数据依特定算法直接指定到一个地址上。我们可以认为hashCode方法返回的就是对象存储的物理地址(实际可能并不是,例 如:通过获取对象的物理地址然后除以8再求余,余数几是计算得到的散列值,我们就认为返回一个不是物理地址的数值,而是一个可以映射到物理地址的值)。
这 样一来,当集合要添加新的元素时,先调用这个元素的hashCode方法,就一下子能定位到它应该放置的物理位置上。如果这个位置上没有元素,它就可以直 接存储在这个位置上,不用再进行任何比较了;如果这个位置上已经有元素了,就调用它的equals方法与新元素进行比较,相同的话就不存了,不相同就散列 其它的地址。所以这里存在一个冲突解决的问题。这样一来实际调用equals方法的次数就大大降低了,几乎只需要一两次。


改写equals时总是要改写hashCode
============================================================
java.lnag.Object中对hashCode的约定:

   1. 在一个应用程序执行期间,如果一个对象的equals方法做比较所用到的信息没有被修改的话,则对该对象调用hashCode方法多次,它必须始终如一地返回同一个整数。
   2. 如果两个对象根据equals(Object o)方法是相等的,则调用这两个对象中任一对象的hashCode方法必须产生相同的整数结果。
   3. 如果两个对象根据equals(Object o)方法是不相等的,则调用这两个对象中任一个对象的hashCode方法,不要求产生不同的整数结果。但如果能不同,则可能提高散列表的性能。


有一个概念要牢记,两个相等对象的equals方法一定为true, 但两个hashcode相等的对象不一定是相等的对象。

所以hashcode相等只能保证两个对象在一个HASH表里的同一条HASH链上,继而通过equals方法才能确定是不是同一对象,如果结果为true, 则认为是同一对象不在插入,否则认为是不同对象继续插入。

Object的代码:
public String toString () {
    return this.getClass().getName() + "@" + Integer.toHexString(this.hashCode());
}

public boolean equals (Object o) {
    return this == o;
}

public native int hashCode();


从上面我们可以看到是否很可能Object.hashCode就是代表内存地址。下面我们来证明hashcode是不是真的就是Object的内存地址呢?实际上,hashcode根本不能代表object的内存地址。
-----------------------------------------
Object.hashCode不可以代表内存地址
---------------------------------------- 

此方法的作用是证明 java.lang.Object的hashcode 不是代表 对象所在内存地址。 
我产生了10000个对象,这10000个对象在内存中是不同的地址,但是实际上这10000个对象
的hashcode的是完全可能相同的

public class TestArrayList {

	public static void main(String[] args) {
		ArrayList list = new ArrayList();
		int numberExist = 0;

		// 证明hashCode的值不是内存地址
		for (int i = 0; i < 10000; i++) {
			Object obj = new Object();
			if (list.contains(obj.toString())) {
				System.out.println(obj.toString() + " exists in the lint." + i);
				numberExist++;
			} else {
				list.add(obj.toString());
			}
		}
		System.out.println("重复个数" + numberExist);
		System.out.println("list size:" + list.size());
	}
}

 

分享到:
评论

相关推荐

    java中hashcode和equals的详解.pdf

    本文详细介绍了 Java 中的 hashCode 和 equals 方法,探讨了这两个方法的作用、实现机制和使用场景。通过对 hashCode 和 equals 方法的深入分析,我们可以更好地理解 Java 集合的实现原理和哈希表的工作机制。 一、...

    我怀疑这是IDEA的BUG,但是我翻遍全网没找到证据!.doc

    1.Lombok @Data 注解的作用和原理:Lombok 的 @Data 注解可以生成类的无参构造函数、get/set 方法、equals 方法、toStrong 方法和 hashCode 方法等。它通过字节码增强技术,直接操作字节码文件来实现这些功能。 2. ...

    oracle-mooc-lambdas-streams-quiz1-question9:演示了针对Lambda和Streams上的Oracle MOOC的测验1中问题9的问题

    l.replace(Integer::hashCode) l.replace(n -&gt; n.hashCode()) l.replaceAll(Integer::hashCode) l.replaceAll(n -&gt; n.hashCode()) l.replaceAll(Number::hashCode) 可能答案的顺序是随机的,并且每次参加测验时都会...

    java培训机构内部预习文档

    集合框架 Collection、List、Set、Map的接口及其实现类、迭代、Hash 算法与 hashCode 方法、comparable、泛型 chp12.异常 概念、分类、产生、传递、处理、自定义异常 chp13.线程 概念、创建、状态转换、数据共享、...

    2023年JAVA面试题资料.doc

    sleep() 和 wait() 都是 Thread 类的方法,但是它们有着不同的作用。sleep() 方法使当前线程休眠指定的时间,但是它不会释放对象锁,而 wait() 方法会释放对象锁。此外,sleep() 方法可以在时间未到时被打断,抛出 ...

    1、scala面试题(25问).pdf

    * 默认实现了toString,equals,hashcode,copy方法 * 样本类可以通过==来比较两个对象 而class是Scala语言中的一个类,需要使用new关键字来构建对象。 6. 隐式转换 Scala语言中的隐式转换函数是指那种以implicit...

    Java综合面试资料集

    2. switch 语句:switch 语句可以作用在 byte、short、int、char 等类型上,但不能作用在 long 或 String 上。 3. 数据类型转换:Java 中可以通过强制类型转换来实现数据类型的转换。 4. 编码方案:Java 采用 ...

    java之Object类方法技术分享PPT

    主要包含Object类中的getClass()、hashCode()、equals()、toString()方法的使用和作用,还包含一个3D旋转模型,还包含几个常见的面试题的解析,可用作学生每周技术分享或者上台演讲,适用于大学计算机专业相关人士。

    day12_Object类、常用API.pdf

    toString()方法的源码中返回类的全限定名字和hashCode()方法返回的int值,可以暂时理解为对象的内存地址。Integer.toHexString()方法将int类型的值转成十六进制。因此调用对象的toString()方法将看到内存的地址值。 ...

    Java面试题.docx

    内部类的作用 5、进程和线程的区别 6、final,finally,finalize的区别 7、Serializable 和Parcelable 的区别 8、静态属性和静态方法是否可以被继承?是否可以被重写?以及原因? 9、成员内部类、静态内部类、...

    sesvc.exe 阿萨德

    如果当前桶有值( Hash 冲突),那么就要比较当前桶中的 key、key 的 hashcode 与写入的 key 是否相等,相等就赋值给 e,在第 8 步的时候会统一进行赋值及返回。 如果当前桶为红黑树,那就要按照红黑树的方式写入数据...

    Java入门教程(微学苑)-part1

    3.12 Java变量的作用域 48 3.13 Java this关键字详解 49 3.14 使用this区分同名变量 49 3.15 作为方法名来初始化对象 50 3.16 作为参数传递 51 3.17 Java方法重载 52 3.18 Java类的基本运行顺序 53 3.19 Java包装类...

    快手真实面试题,不多,但真实

    6. hashCode 的作用和哈希冲突的解决 7. Java 的访问修饰符默认的是什么? 8. static 的用法和静态方法加锁的效果 9. Java 四种引用类型:强引用、软引用、弱引用、幻象引用 10. 悲观锁和乐观锁的区别 二、Android ...

    安卓java读取网页源码-interview:安卓面试

    内部类、静态内部类、局部内部类和匿名内部类的区别及作用? == 和 equals() 和 hashCode() 的区别? Integer 和 int 之间的区别? String 转换成 Integer 的方式及原理? 自动装箱实现原理?类型转换实现原理? 对 ...

    涵盖了90%以上的面试题

    为什么重写equals还要重写hashCode? 介绍一下volatile jdk1.5新特性 jdk1.7新特性 jdk1.8新特性 java语言有哪些优点? 同一个.java文件中是否可以有多个main方法 一个".java"源文件中是否可以包括多个类(不是内部类...

    史上最全java面试,103项重点知识,带目录

    3. 两个对象的 hashCode()相同,则 equals()也一定为 true,对吗? 3 4. final 在 java 中有什么作用? 4 5. java 中的 Math.round(-1.5) 等于多少? 4 6. String 属于基础的数据类型吗? 4 7. java 中操作字符串都...

    2022 最全 Java 面试笔试题汇总

    * Hashcode 和 equals 方法的联系是什么?什么是重写和重载? * Java 中 final 关键字的作用是什么?java 中的反射机制是什么? * Java 如何高效进行数组拷贝?成员变量和方法的区别是什么? Java Web * Cookie 和...

    Java-常见面试题.pdf

    * hashCode():该方法用于哈希查找,重写了 equals 方法一般都要重写 hashCode 方法。这个方法在一些具有哈希功能的 Collection 中用到。 * getClass():final 方法,获得运行时类型。 * wait():使当前线程等待该...

    写给大忙人看的JAVA SE 8

    1.6 变量作用域 10 1.7 默认方法 14 1.8 接口中的静态方法 17 练习 18 第2章 Stream API 20 2.1 从迭代器到Stream操作 22 2.2 创建Stream 23 2.3 filter、map和flatMap方法 25 2.4 提取子流和组合流 26 2.5 有状态的...

    Java常见面试题208道.docx

    3.两个对象的 hashCode()相同,则 equals()也一定为 true,对吗? 4.final 在 java 中有什么作用? 5.java 中的 Math.round(-1.5) 等于多少? 6.String 属于基础的数据类型吗? 7.java 中操作字符串都有哪些类?它们...

Global site tag (gtag.js) - Google Analytics