热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

关于Equal和HashCode的实现

重点提示:Equals示例:PublicOverridesFunctionEquals(ByValobjAsObject

 

重点提示:

Equals示例:

Public Overrides Function Equals(ByVal obj As Object) As Boolean

'Check for null and compare run-time types.

If obj Is Nothing OrElse Not [GetType]().Equals(obj.GetType()) Then

Return False

End If

Dim p As Point = CType(obj, Point)

Return x = p.x AndAlso y = p.y

End Function 'Equals


public override bool Equals(Object obj) {

//Check for null and compare run-time types.

if (obj == null || GetType() != obj.GetType()) return false;

Point p = (Point)obj;

return (x == p.x) && (y == p.y);

}

GetHashCode示例:

Public Overrides Function GetHashCode() As Integer

Return a.GetHashCode() Xor b.GetHashCode() Xor c.GetHashCode()

End Function


public override int GetHashCode () {

return a.GetHashCode() ^ b.GetHashCode() ^ c.GetHashCode();

}



首先是几篇比较有意义的内容:


equals()反映的是对象或变量具体的值。

hashCode()是对象或变量通过哈希算法计算出的哈希值。

之所以有hashCode方法,是因为在批量的对象比较中,hashCode要比equals来得快,很多集合都用到了hashCode,比如HashTable


两个obj,如果equals()相等,hashCode()一定相等。

两个obj,如果hashCode()相等,equals()不一定相等(Hash散列值有冲突的情况,虽然概率很低)。

所以:

可以考虑在集合中,判断两个对象是否相等的规则是:

第一步,如果hashCode()相等,则查看第二步,否则不相等;

第二步,查看equals()是否相等,如果相等,则两obj相等,否则还是不相等。



1、首先equals()hashcode()这两个方法都是从object类中继承过来的。

equals()是对两个对象的地址值进行的比较(即比较引用是否相同)。

hashCode()是一个本地方法,它的实现是根据本地机器相关的。


2Java语言对equals()的要求如下,这些要求是必须遵循的:

? 对称性:如果x.equals(y)返回是“true”,那么y.equals(x)也应该返回是“true”

? 反射性:x.equals(x)必须返回是“true”

? 类推性:如果x.equals(y)返回是“true”,而且y.equals(z)返回是“true”,那么z.equals(x)也应该返回是“true”

? 一致性:如果x.equals(y)返回是“true”,只要xy内容一直不变,不管你重复x.equals(y)多少次,返回都是“true”

? 任何情况下,x.equals(null),永远返回是“false”x.equals(x不同类型的对象)永远返回是“false”


3equals()相等的两个对象,hashcode()一定相等;

反过来:hashcode()不等,一定能推出equals()也不等;

hashcode()相等,equals()可能相等,也可能不等。

引用:http://honda418.javaeye.com/blog/342731


Effective Java

讲得比较详细

equals()方法

1. 自反

2. 对称

3. 传递

4. 一致

5X非空,x.equals(null)返回false


为了实现高质量的equals()改写,effective java提醒我们要注意一下几点:

1. 使用==操作符检查是否指向同一个对象,这是一个性能优化的手段。

2. 使用instanceof来检查是否为某个类,同样也是性能优化的手段。

3. 把实参转换到正确的类型,上面一步保证了这一步不会有错误。

4. 检查类里的每一个关键域是否都相等。


hashCode()则是一种计算 对象的散列值



任何 classes 如果复写了 equals(), 便应该同时也复写 hashCode()


我的理解:

两个函数都是用来比较两个对象是否相等的。默认情况下,这两个函数通过比较两个对象的地址是否一致来判断两个对象是否相等。也就是说,两个对象只有拥有相同的引用,才可能保证equalhashcode的相同。

如果我们仅仅需要比较地址,则没必要重写这两个函数。但是现实情况是,我们有时候需要通过比较对象的值来判定两个对象是否相等。比如下面这个类:

Public Class Point

Public x as Integer

Public y as Integer

End Class

我们定义两个对象:Point1Point2对象:

Dim Point1 as Point=New Point()

Dim Point2 as Point=New Point()

Point1.x=1

Point1.y=1

Point2.x=1

Point2.y=1

很明显,Point1Point2对应相同的点(1,1),他们的值是相同的,但是如果使用equalhashcode来比较两个对象,他们却是不同的,因为他们在内存中是两个独立的对象,地址不一样。

我们需要的功能是比较值而不是地址,这时我们就需要重写Equal函数和GetHashCode函数,让他们来比较值相等。下面就是示例代码:

Equals() :

http://msdn.microsoft.com/en-us/library/bsc2ak47.aspx

Visual Basic :

Imports System


Class Point

Inherits Object

Protected x, y As Integer


Public Sub New()

Me.x = 0

Me.y = 0

End Sub 'New


Public Sub New(ByVal X As Integer, ByVal Y As Integer)

Me.x = X

Me.y = Y

End Sub 'New


Public Overrides Function Equals(ByVal obj As Object) As Boolean

'Check for null and compare run-time types.

If obj Is Nothing OrElse Not [GetType]().Equals(obj.GetType()) Then

Return False

End If

Dim p As Point = CType(obj, Point)

Return x = p.x AndAlso y = p.y

End Function 'Equals


Public Overrides Function GetHashCode() As Integer

Return x ^ y

End Function 'GetHashCode

End Class 'Point


Class Point3D

Inherits Point

Private z As Integer


Public Sub New(ByVal X As Integer, ByVal Y As Integer, ByVal Z As Integer)

Me.x = X

Me.y = Y

Me.z = Z

End Sub 'New


Public Overrides Function Equals(ByVal obj As Object) As Boolean

Return MyBase.Equals(obj) AndAlso z = CType(obj, Point3D).z

End Function 'Equals


Public Overrides Function GetHashCode() As Integer

Return MyBase.GetHashCode() ^ z

End Function 'GetHashCode

End Class 'Point3D


Class [MyClass]

Public Shared Sub Main()

Dim point2D As New Point(5, 5)

Dim point3Da As New Point3D(5, 5, 2)

Dim point3Db As New Point3D(5, 5, 2)


If Not point2D.Equals(point3Da) Then

Console.WriteLine("point2D does not equal point3Da.")

End If

If Not point3Db.Equals(point2D) Then

Console.WriteLine("Likewise, point3Db does not equal point2D.")

End If

If point3Da.Equals(point3Db) Then

Console.WriteLine("However, point3Da equals point3Db.")

End If


End Sub 'Main

End Class '[MyClass]

' ----------------------------------

' Output should be:

'

' point2D does not equal point3Da.

' Likewise, point3Db does not equal point2D.

' However, point3Da equals point3Db.



C# :

using System;


class Point: Object {

protected int x, y;


public Point() {

this.x = 0;

this.y = 0;

}


public Point(int X, int Y) {

this.x = X;

this.y = Y;

}


public override bool Equals(Object obj) {

//Check for null and compare run-time types.

if (obj == null || GetType() != obj.GetType()) return false;

Point p = (Point)obj;

return (x == p.x) && (y == p.y);

}


public override int GetHashCode() {

return x ^ y;

}

}



class Point3D: Point {

int z;


public Point3D(int X, int Y, int Z) {

this.x = X;

this.y = Y;

this.z = Z;

}


public override bool Equals(Object obj) {

return base.Equals(obj) && z == ((Point3D)obj).z;

}


public override int GetHashCode() {

return base.GetHashCode() ^ z;

}

}


class MyClass {


public static void Main() {

Point point2D = new Point(5, 5);

Point3D point3Da = new Point3D(5, 5, 2);

Point3D point3Db = new Point3D(5, 5, 2);


if (!point2D.Equals(point3Da)) {

Console.WriteLine("point2D does not equal point3Da.");

}

if (!point3Db.Equals(point2D)) {

Console.WriteLine("Likewise, point3Db does not equal point2D.");

}

if (point3Da.Equals(point3Db)) {

Console.WriteLine("However, point3Da equals point3Db.");

}


}

}

// ----------------------------------

// Output should be:

//

// point2D does not equal point3Da.

// Likewise, point3Db does not equal point2D.

// However, point3Da equals point3Db.


GetHashCode() :

http://msdn.microsoft.com/en-us/library/system.object.gethashcode.aspx

Visual Basic :

Imports System


Public Class SomeType

Public Overrides Function GetHashCode() As Integer

Return 0

End Function

End Class



Public Class AnotherType

Public Overrides Function GetHashCode() As Integer

Return 1

End Function

End Class


Public Class LastType

Public Overrides Function GetHashCode() As Integer

Return 2

End Function

End Class


Public Class Demo

Private a As New SomeType()

Private b As New AnotherType()

Private c As New LastType()


Public Overrides Function GetHashCode() As Integer

Return a.GetHashCode() Xor b.GetHashCode() Xor c.GetHashCode()

End Function

End Class



C# :

using System;


public class SomeType {

public override int GetHashCode() {

return 0;

}

}


public class AnotherType {

public override int GetHashCode() {

return 1;

}

}


public class LastType {

public override int GetHashCode() {

return 2;

}

}


public class MyClass {

SomeType a = new SomeType();

AnotherType b = new AnotherType();

LastType c = new LastType();


public override int GetHashCode () {

return a.GetHashCode() ^ b.GetHashCode() ^ c.GetHashCode();

}

}


几种常见的HashCode计算方法:

http://www.javaeye.com/topic/170219

1、 把某个非零常数值,比如17,保存在一个叫result的int类型的变量中。

2、 对于对象中的关键域f(指equals方法中考虑的每一个域),完成以下步骤:

A、为该域计算int类型的散列码c:

I、如果该域是boolean类型,则计算(f ? 0 : 1)。

II、如果该域是byte、char、short或者int类型,则计算(int)f。

III、如果该域是long类型,则计算(int)(f ^ f ( f >> 32 ) )。

IV、如果该域是float类型,则计算Float.floatToInitBits( f )。

V、如果该域是double类型,则计算Double.doubleToLongBits( f )得到一个long类型的值,再执行步骤III。

VI、如果该域是一个对象引用,并且该类的equals方法通过递归调用equals的方式来比较这个域,则同样对这个递归调用hashCode。如果要求一个更为复杂的比较,则为这个域计算一个规范表示,然后针对这个范式表示调用hashCode。如果这个域为NULL,则返回0或者其他常数。

VII、如果该域是一个数组,则把每个元素当作单独的域来处理。也就是说,递归地应用上述规则,对每个重要的元素计算一个散列码,然后根据步骤B中的做法把这些散列码组合起来。

B、按照下面的公式,把上面步骤的C组合到result中:

result = 17 * result + c;

3、 返回result。

4、 写完后测试是否相等的实例具有相同的散列码。


推荐阅读
  • 在多线程并发环境中,普通变量的操作往往是线程不安全的。本文通过一个简单的例子,展示了如何使用 AtomicInteger 类及其核心的 CAS 无锁算法来保证线程安全。 ... [详细]
  • 字节流(InputStream和OutputStream),字节流读写文件,字节流的缓冲区,字节缓冲流
    字节流抽象类InputStream和OutputStream是字节流的顶级父类所有的字节输入流都继承自InputStream,所有的输出流都继承子OutputStreamInput ... [详细]
  • 检查在所有可能的“?”替换中,给定的二进制字符串中是否出现子字符串“10”带 1 或 0 ... [详细]
  • 属性类 `Properties` 是 `Hashtable` 类的子类,用于存储键值对形式的数据。该类在 Java 中广泛应用于配置文件的读取与写入,支持字符串类型的键和值。通过 `Properties` 类,开发者可以方便地进行配置信息的管理,确保应用程序的灵活性和可维护性。此外,`Properties` 类还提供了加载和保存属性文件的方法,使其在实际开发中具有较高的实用价值。 ... [详细]
  • JComponentJLabel的setBorder前言用例2205262241前言setBorder(Border边框)实现自JComponentjava.awt.Insets ... [详细]
  • 如何在Java中使用DButils类
    这期内容当中小编将会给大家带来有关如何在Java中使用DButils类,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。D ... [详细]
  • 本题探讨如何编写程序来计算一个数值的整数次方,涉及多种情况的处理。 ... [详细]
  • 本文详细解析了客户端与服务器之间的交互过程,重点介绍了Socket通信机制。IP地址由32位的4个8位二进制数组成,分为网络地址和主机地址两部分。通过使用 `ipconfig /all` 命令,用户可以查看详细的IP配置信息。此外,文章还介绍了如何使用 `ping` 命令测试网络连通性,例如 `ping 127.0.0.1` 可以检测本机网络是否正常。这些技术细节对于理解网络通信的基本原理具有重要意义。 ... [详细]
  • 在处理 XML 数据时,如果需要解析 `` 标签的内容,可以采用 Pull 解析方法。Pull 解析是一种高效的 XML 解析方式,适用于流式数据处理。具体实现中,可以通过 Java 的 `XmlPullParser` 或其他类似的库来逐步读取和解析 XML 文档中的 `` 元素。这样不仅能够提高解析效率,还能减少内存占用。本文将详细介绍如何使用 Pull 解析方法来提取 `` 标签的内容,并提供一个示例代码,帮助开发者快速解决问题。 ... [详细]
  • 【刷题篇】Java 不用Math.sqrt() 如何求一个数的平方根
    题目:在不用Math.sqrt()方法中如何求解一个大于1的数的平方根题解一、牛顿迭代法计算x2n的解,令f(x)x2-n,相当于求解f( ... [详细]
  • 本教程详细介绍了如何使用 Spring Boot 创建一个简单的 Hello World 应用程序。适合初学者快速上手。 ... [详细]
  • 原文网址:https:www.cnblogs.comysoceanp7476379.html目录1、AOP什么?2、需求3、解决办法1:使用静态代理4 ... [详细]
  • Java高并发与多线程(二):线程的实现方式详解
    本文将深入探讨Java中线程的三种主要实现方式,包括继承Thread类、实现Runnable接口和实现Callable接口,并分析它们之间的异同及其应用场景。 ... [详细]
  • 在 Java 中,`join()` 方法用于使当前线程暂停,直到指定的线程执行完毕后再继续执行。此外,`join(long millis)` 方法允许当前线程在指定的毫秒数后继续执行。 ... [详细]
  • 在本阶段的Java编程实战中,我们将深入探讨位运算的应用。具体任务是实现逻辑位运算。用户需从键盘输入一个位运算符(如AND、OR、XOR或NOT)及相应的操作数,系统将根据输入的运算符执行相应的位运算并输出结果。此练习旨在加强学员对位运算的理解和实际操作能力。 ... [详细]
author-avatar
mobiledu2502891563
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有