西安新闻网

Java中的hashCode() 和 equals()的若干问题解答

Java对象类:

中存在一种方法

public native int hashcode();

根据此方法的声明,该方法返回int类型的值,并且是本地方法,因此在对象类中没有给出具体的实现。为什么对象类需要这样的方法?它是做什么的?

让我举个例子:

假设内存中有0 1 2 3 4 5 6 7 8。如果我有一个名为ID的字段,那么我想将此字段存储在上述8个位置之一中。如果我不使用HashCode,我可以存储它。搜索时,您需要前往8个位置才能找到一个。使用HashCode效率更高。放入HashCode%8的ID,然后将ID存储在获取余数的位置。然后,每次查找类时,都可以使用ID的HashCode%8直接找到存储的位置。如果HashCode%8的ID已经由位置本身计算怎么办?这取决于算法的实现。例如,ThreadLocal中的做法是从计算的位置找到第一个空位置并放置数据。 HashMap方法通过链结构连接。无论如何,只要保证在采用时与算法保持一致。如果ID的HashCode%8相等(这对应于前一句中描述的链结构的场景)怎么办?此时你需要定义equals。首先,使用HashCode%8确定类的位置,然后使用equals在此位置查找所需的类。比较这两个类也是类似的,首先通过HashCode比较,如果HashCode相等然后确定等于。如果两个类的HashCodes不同,那么这两个类必须是不同的。

另一个实际例子是Set。我们知道集合中的元素是不可重复的,那么我们该怎么做呢? Set基于equals()方法来确定两个元素是否相等。例如,Set中有1000个元素。当第1001个元素进入时,它可以调用equals方法最多1000次。如果等于方法很复杂并且存在许多对比,则效率将大大降低。使用HashCode是不同的,例如,HashSet。底层基于HashMap。首先,我们通过HashCode获取一个模块,然后将其修复到某个位置。如果此位置中没有元素,那么我们可以确定HashSet中不能有任何元素,并且可以直接存储新元素equals。如果在这个位置有元素,比较一个,首先比较HashCode,HashCode不同然后不需要比较,它必须不同,HashCode是相等的,然后等于比较,没有相同的元素,有没有相同的元素。如果原始Set中有相同的元素,只要HashCode定义良好(不重复),无论Set中有多少元素,它只需要执行一次equals。这样,大大减少了对equals方法的调用次数,提高了效率。

因此hashCode的作用是找到域(以查找集合区域中对象的位置)。 HashCode可以将集合划分为多个区域,每个对象可以计算其哈希码,并且每个组可以分组为哈希码。每个分组对应于存储区域。根据对象的哈希码,可以确定对象的存储区域,大大减少了查询匹配元素的数量,增强了查询。效率。

也就是说,hashCode()的目的是获取哈希码,也称为哈希码;它实际上返回一个int整数。此哈希码的目的是确定哈希表中对象的索引位置。

hashCode()在JDK的Object.java中定义,这意味着Java中的任何类都包含hashCode()函数。

虽然,每个Java类都包含hashCode()函数。但是,类的hashCode()仅在创建“类的哈希列表”时有用(参见下面的“哈希表”)(角色是:确定哈希表中类的每个对象的位置)在其他情况下(例如,创建类的单个对象,或创建类的对象数组等),类的hashCode()无效。

上面的哈希表指的是Java集合中的类,它们本质上是哈希表,例如HashMap,Hashtable和HashSet。

也就是说:hashCode()在哈希表中很有用,在其他情况下没用。哈希表中hashCode()的目的是获取对象的哈希码并确定哈希表中对象的位置。

好!此时,我们发现hashCode()的作用是获取哈希码。但是用于什么是哈希码呢?以下是哈希码的作用简介。

我们都知道哈希表存储键值对,其特征在于能够基于“键”快速检索相应的“值”。这使用哈希码!哈希表的本质是由数组实现的。当我们想在哈希表中获得“值”时,我们实际上想要在数组中的某个位置获取一个元素。阵列的位置由“键”获得;此外,通过对应于“密钥”的哈希码计算阵列的位置。

下面我以HashTable为例来说明hashCode对象的重要性。

对象必然具有多个属性。如何选择属性来执行散列测试一个人的设计能力。如果我们哈希所有的属性,这肯定是一个糟糕的设计,因为对象的hashCode方法并不是一直调用,如果太多的属性参与哈希,那么所需的操作数时间会大大增加,这会严重影响该计划的表现。但是,如果较少的属参与哈希,则哈希的多样性将被削弱,并且将产生大量的哈希“冲突”。除了不能充分利用空间外,还会在一定程度上影响对象的查询效率。事实上,这两者是矛盾的,哈希的多样性将导致性能下降。

那么如何设计对象的hashCode,LZ没有经验。我从Internet找到了一个解决方案:设置一个缓存标识符来缓存当前的哈希码,只在参与哈希的对象发生变化时重新计算,否则调用缓存的哈希码,这可以大大提高性能。

在HashTable中计算table []数组中对象的索引位置,代码如下:

Int index=hash&0x7FFFFFFF)%标签。长度;

为什么&0x7FFFFF?因为某些对象的hashCode可能是负数,所以使用0x7FFFFFFF运行可确保索引是正数。通过这一步,我可以直接找到一个对象,所以理论上我们可以使用hashCode直接在对象的Hash列表中定位该位置。但为什么有一个键值对使用key的hashCode存储数据而不是直接存储值?这是与HashTable性能问题相关的最重要问题:哈希冲突!

我们知道冲突的产生是因为不同的对象产生相同的哈希码。如果我们设计对象的哈希码以确保99.%不重复,但是有一个绝对的,几乎不可能的冲突是你无法避免的。我们知道hashcode返回int,其值只能在int范围内。如果我们存储的数据多于int,该怎么办?这将不可避免地导致两个相同的索引,其中两个对象存储在索引位置,我们可以使用密钥本身进行判断。因此索引对象的索引位置中有许多对象。我们必须依赖密钥的hashCode和密钥本身来区分它们。

Equals()用于确定两个对象是否相等。

Equals()在JDK的Object中定义。 java的。通过判断两个对象的地址是否相等(即,它们是否是同一个对象),我们可以区分它们是否相等。源代码如下:

公共布尔值等于(Object obj){

返回(这==obj);

}

由于equals()方法是在Object.java中定义的,这意味着所有Java类都实现了equals()方法,并且所有类都可以通过equals()比较两个对象的相等性。但是,正如我们已经说过的,使用默认的“equals()”方法等同于“==”方法。因此,我们通常覆盖equals()方法:如果两个对象的内容相等,则equals()方法返回true;否则,它返回fasle。

根据类是否重写equals()方法,以下内容分为2类。

(01)如果一个类没有覆盖equals()方法,当它用equals()比较两个对象时,它实际上会比较两个对象是否是同一个对象。此时,它相当于通过“==”比较两个对象。

(02)我们可以覆盖类的equals()方法,让equals()以其他方式比较两个对象的相等性。通常的做法是:如果两个对象的内容相等,则equals()方法返回true;否则,它返回fasle。

==:其目的是确定两个对象的地址是否相等。也就是说,确定两个对象是否是同一对象。

Equals():它的作用也是确定两个对象是否相等。但它通常有两种用途(上面详细描述):

情况1,该类不会覆盖equals()方法。当用equals()比较类的两个对象时,它相当于用“==”比较两个对象。

情况2,该类涵盖了equals()方法。通常,我们重写equals()方法来比较两个对象的内容相等;如果它们的内容相等,则它们返回true(即,两个对象被认为是相等的)。

在两种情况下,我们使用“使用类”来描述“hashCode()和equals()之间的关系”。

1,第一个不会创建“特定于类的哈希表”

这里的短语“不创建对应于该类的哈希表”意味着我们不会在HashSet,Hashtable,HashMap等的数据结构中使用该类,这本质上是一个哈希表。例如,将不会创建此类的HashSet集合。

在这种情况下,此类的“hashCode()和equals()”没有半融资关系!在这种情况下,equals()用于比较类的两个对象的相等性。 hashCode()完全没有效果,所以忽略hashCode()。

2,第二个将创建“特定于类的哈希表”

这里,“将创建对应于该类的哈希表”意味着:我们将在HashSet,Hashtable,HashMap等的数据结构中使用此类,这本质上是一个哈希表。例如,创建此类的HashSet集合。

在这种情况下,类的“hashCode()和equals()”是相关的:

1)如果两个对象相等,则它们的hashCode()值必须相同。这里的平等是指在使用equals()比较两个对象时返回true。

2)如果两个对象hashCode()相等,则它们不一定相等。

因为在散列列表中,hashCode()是相等的,即两个键值对的散列值相等。但是,如果散列值相等,则不一定可能获得相同的键值。要添加“两个不同的键值对具有相同的哈希值”,这是哈希冲突。

另外,在这种情况下。要确定两个对象是否相等,我们不仅需要覆盖equals(),还需要覆盖hashCode()函数。否则,equals()无效。例如,要创建Person类的HashSet集合,必须同时覆盖Person类的equals()和hashCode()方法。如果你只是覆盖equals()方法。我们会发现equals()方法没有达到预期的效果。

这些是我在Java中解决的一些hashCode()和equals()问题的答案。

只有代表个人意见,如果您有疑问,请在下面留言进行沟通。

http://www.sugys.com/bdsbIc.html