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());
}
}
分享到:
相关推荐
hashCode 的作用 hashCode 的主要作用是用于查找和排序。在查找和排序的过程中,我们需要快速地定位到目标对象,而 hashCode 正是这个过程的关键。例如,在内存中有 8 个位置,分别是 0 1 2 3 4 5 6 7,我们可以...
该方法的主要作用是返回一个整数,这个整数通常被用来作为哈希表中元素的索引。 #### 1.1 哈希算法简介 哈希算法是一种将任意长度的数据映射为固定长度的算法。简单来说,哈希算法就是将输入数据转换为一个特定的...
本文详细介绍了 Java 中的 hashCode 和 equals 方法,探讨了这两个方法的作用、实现机制和使用场景。通过对 hashCode 和 equals 方法的深入分析,我们可以更好地理解 Java 集合的实现原理和哈希表的工作机制。 一、...
Java中的hashCode方法是每个类都需要实现的重要方法之一,它的主要作用是将对象的数据转换为一个32位的整数,用于标识对象的唯一性。在Java的所有类中,Object类是最顶层的父类,它定义了hashCode方法,该方法返回...
接下来,我们将详细探讨它们的作用、关系以及在实际开发中的应用。 首先,`equals()`方法是Java中用来判断两个对象是否逻辑相等的。当我们说两个对象逻辑相等,意味着它们具有相同的属性和状态,即使它们在内存中的...
"关于Object中equals方法和hashCode方法判断...equals 和 hashCode 方法都是用于比较两个对象是否相同的,但它们的实现机理和作用域却有所不同。通过重写这两个方法,我们可以更好地比较对象的内容,并避免对象的重复。
在Java编程中,`equals()`和`hashCode()`方法是Object类中的两个重要方法,它们在比较和处理对象时起着至关重要的作用。`equals()`方法用于判断两个对象是否相等,而`hashCode()`方法则与对象在哈希表中的存储位置...
- **`hashCode()`方法的作用**:当向哈希表中插入新对象时,Java会先调用该对象的`hashCode()`方法来确定其存储位置。如果该位置为空,则直接存放对象;如果该位置已有对象,则进一步调用`equals()`方法判断新旧对象...
Java中的`hashCode`方法是Java编程语言中的一个重要概念,它主要与对象的散列处理相关。在Java的`Object`类中定义了一个本地方法(native)`hashCode()`,该方法返回一个`int`类型的数值。这个数值是根据对象的状态...
哈希码(HashCode)的名字来源于计算机科学中的哈希函数,这是一种将任意大小的数据映射为固定大小输出(通常为整数)的函数,它在数据结构如哈希表和分布式计算中起着关键作用。 【哈希函数】是此竞赛中的重要概念...
在Java编程语言中,对象转型和多态是面向对象编程的重要概念,它们在软件设计和实现中发挥着关键作用。本文将深入探讨Object类、对象转型(向上转型和向下转型)以及多态的概念。 **第一节: Object类** Object类...
1.Lombok @Data 注解的作用和原理:Lombok 的 @Data 注解可以生成类的无参构造函数、get/set 方法、equals 方法、toStrong 方法和 hashCode 方法等。它通过字节码增强技术,直接操作字节码文件来实现这些功能。 2. ...
八、HashCode的作用 在Java集合中,特别是Set接口的实现,如HashSet,使用哈希算法来存储和查找元素。通过对象的hashCode(),Set可以快速定位元素位置,提高查找效率。如果两个对象equals()相等,它们的hashCode()...
Java高新技术涵盖了许多关键概念,这些概念在现代软件开发中起着至关重要的作用。以下是一些主要知识点的详细说明: 1. **静态导入**:在Java中,`import static`关键字允许我们直接使用类中的静态成员,而无需通过...
hashCode() 方法返回一个对象的哈希码,而 equals() 方法比较两个对象的实际值是否相等。 十五、自动拆装箱 自动拆装箱是 Java 中的一种机制,它可以自动将基本类型转换为对应的包装类型,反之亦然。但是,自动拆...
Java 开发常用的 jar 包的作用解释 Java 开发中,jar 包是不可或缺的一部分。jar 包可以提供各种功能,例如 IO 操作、反射和自省、字符串操作、数学运算等等。在本文中,我们将对常用的 jar 包进行详细的解释。 1....
l.replace(Integer::hashCode) l.replace(n -> n.hashCode()) l.replaceAll(Integer::hashCode) l.replaceAll(n -> n.hashCode()) l.replaceAll(Number::hashCode) 可能答案的顺序是随机的,并且每次参加测验时都会...
当我们需要将字符串形式的数据转换为Java对象时,属性编辑器就发挥了关键作用。例如,从请求参数或配置文件中读取的字符串可能需要转换为日期、颜色代码或其他自定义类型。这篇博客“spring 自定义属性编辑器”可能...
- **converter的作用**:主要负责数据类型的转换工作,即将表单域中的数据类型转换为JavaBean中的数据类型,反之亦然。 - **未指定converter的影响**:如果在使用`<rich:listShuttle>`时没有正确设置`converter`属性...
toString() 方法的主要作用是将对象转换为字符串形式,以便于输出或显示。 toString() 方法的默认实现是返回一个字符串,该字符串由类名、at 标记符“@”和对象的哈希码的无符号十六进制表示组成。例如,Object ...