`
xifangyuhui
  • 浏览: 188565 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

对java中equals和hashCode函数的一些理解1(转)

阅读更多

JDK的java.lang.Object类中实现了equals函数,其定义说明如下: 

其具体的实现代码如下所示: 

Java代码
  1. public boolean equals(Object obj) {  
  2.     return (this == obj);  
  3. }    


     从上面的代码中可以看出,Object类的equals实现只是简单地调用了“==”运算符,也即定义中说明的,对于两个非空对象X和Y,有且仅当X和Y指向同一个对象时该函数才返回true。由于Object类是java中所有类的超类,因而其它任何类都默认继承了此函数。在大多数情况下,此默认的实现方式是合适的,因为任一个类本质上都是唯一的;但是对于那些表示“值”的类(如Integer、String等),它们引入了自己特有的“逻辑相等”的概念,此时就必须修改equals函数的实现。 
例如java.lang.String类的实现如下: 

Java代码
  1.    public boolean equals(Object anObject) {  
  2.        if (this == anObject) {  
  3.     return true;  
  4. }  
  5. if (anObject instanceof String) {  
  6.     String anotherString = (String)anObject;  
  7.     int n = count;  
  8.     if (n == anotherString.count) {  
  9.     char v1[] = value;  
  10.     char v2[] = anotherString.value;  
  11.     int i = offset;  
  12.     int j = anotherString.offset;  
  13.     while (n-- != 0) {  
  14.         if (v1[i++] != v2[j++])  
  15.         return false;  
  16.     }  
  17.     return true;  
  18.     }  
  19. }  
  20. return false;  
  21.    }  


而java.lang.Integer类的实现如下: 

Java代码
  1. public boolean equals(Object obj) {  
  2.     if (obj instanceof Integer) {  
  3.         return value == ((Integer)obj).intValue();  
  4.     }  
  5.     return false;  
  6.     }  


      String类的equals实现使得当两个String对象所表示的字符串的值是一样的时候就能返回true;而Integer类则当两个Integer对象所持有的整数值是一样的时候就能返回true。 
      因此,当我们我们自己编写的类需要引入“逻辑相等”的概念,且其超类又没有改写equals的实现时,我们就必须实现自己的equals函数。在上面Object类中关于equals函数的说明中,定义了5条改写equals函数所必须遵守的规范。其中第1条自反性(reflexivity)和第5条通常能够自行满足。下面我们重点介绍下第2点对称性(symmetric)、第3点传递性(transitive)和第4点一致性(consistent)。 
      对称性 
即对于任意两个引用值X和Y,X.equals(Y) 和 Y.equals(X) 返回的结果必须是一致的。下面引用《effect java》上的例子来说明了违反这一特性的后果: 

Java代码
  1. public class CaseInsensitiveString {  
  2.       
  3.     private String s;  
  4.       
  5.     public boolean equals(Object obj){  
  6.         if(obj instanceof CaseInsensitiveString)  
  7.             return s.equalsIgnoreCase(((CaseInsensitiveString)obj).s);  
  8.         if(obj instanceof String)  
  9.             return s.equalsIgnoreCase((String)obj);  
  10.         return false;  
  11.     }  
  12. }  


然后我们定义如下的类来进行测试: 

Java代码
  1. public void test(){  
  2.     CaseInsensitiveString cis = new CaseInsensitiveString("Value");  
  3.     String s = "Value";  
  4.     List list = new ArrayList();  
  5.     list.add(cis);  
  6.     System.out.println(cis.equals(s));  
  7.     System.out.println(s.equals(cis));  
  8.     System.out.println(list.contains(s));  
  9. }  


运行test(),第一条语句的输出为true,而后两条为false。因为CaseInsensitiveString类中equals函数对String对象的比较也可能返回true,只要其大小写不敏感的字符串值相等;而在String类中对任何非String对象都返回false,这样CaseInsensitiveString的实现就违反了对称性,从而导致了第三条语句也返回了意想不到的结果false。这是因为ArrayList的contains函数实现是用实参s对list中每一个对象调用equals函数,若有equals函数返回true,则contains返回true;因而在这里contains函数必然返回false。因此,如果违反了对称性,则可能会得到意料之外的结果。解决此问题的一个办法就是在CaseInsensitiveString类的equals函数中对Stirng对象的比较无论值是否一致都返回false。 
      传递性 
即对于任意的引用值X、Y和Z,如果 X.equals(Y) 和 Y.equals(Z) 都返回true,则 X.equals(Z) 也一定返回true。下面举例说明: 

Java代码
  1.  public class Point {  
  2.     private final int x;  
  3.   
  4.     private final int y;  
  5.   
  6.     public Point(int x, int y) {  
  7.         this.x = x;  
  8.         this.y = y;  
  9.     }  
  10.   
  11.     public boolean equals(Object obj) {  
  12.         if (!(obj instanceof Point))  
  13.             return false;  
  14.         Point p = (Point) obj;  
  15.         return p.x == x && p.y == y;  
  16.     }  
  17. }  
  18.   
  19. public class ColorPoint extends Point {  
  20.   
  21.     private int z;  
  22.   
  23.     public ColorPoint(int x, int y, int z) {  
  24.         super(x, y);  
  25.         this.z = z;  
  26.     }  
  27.   
  28.     public boolean equals(Object obj) {  
  29.         if (!(obj instanceof ColorPoint))  
  30.             return false;  
  31.         ColorPoint cp = (ColorPoint) obj;  
  32.         return super.equals(obj) && cp.z == this.z;  
  33.     }  
  34. }  


在上面的代码中定义了类Point及其子类ColorPoint,并分别改写了equals函数。下面运行如下代码来测试: 

Java代码
  1. ColorPoint cp1 = new ColorPoint(1,2,3);  
  2. ColorPoint cp2 = new ColorPoint(1,2,4);  
  3. Point p = new Point(1,2);  
  4. System.out.println(cp1.equals(p));  
  5. System.out.println(p.equals(cp2));  
  6. System.out.println(cp1.equals(cp2));  


结果前两条语句输出“true”,而最后一条语句输出为“false”;从而违反了传递性规范。其主要原因是在基类的equals函数中并未对子类加以区分,从而使得基类与子类之间的比较也能返回true。要解决此方法,《effect java》上提供了“复合代替继承”的方法;另外,如果可以将基类和子类视为不等的话,使用 getClass()函数代替 instanceof 运算符进行比较可以很好的解决这一问题。getClass()会返回此对象的运行期类(runtime class),因为基类和子类属于不同的class,getClass()能够将其区分开来。下面是一段示例的代码: 

Java代码
  1. public boolean equals(Object obj) {  
  2.         if(obj.getClass() != this.getClass())  
  3.             return false;  
  4.         Point p = (Point) obj;  
  5.         return p.x == x && p.y == y;  
  6.           
  7.     }  


      

分享到:
评论

相关推荐

    Java中的equals和hashCode方法详解1

    在Java编程语言中,`equals()`和`hashCode()`方法是对象的基本组成部分,它们主要用于对象的比较和存储。这两个方法在`java.lang.Object`类中定义,因此所有的Java类都默认继承了这两个方法。然而,根据具体的应用...

    java中equals()函数的用法 equals和==的区别

    在Java编程语言中,`equals()`方法和`==`运算符是两个经常被用来比较对象是否相等的关键概念。理解它们的区别对于编写出正确、健壮的代码至关重要。 首先,`==`运算符用于基本类型(如int, char, boolean)的比较,...

    解析Java对象的equals()和hashCode()的使用

    在Java语言中,equals()和hashCode()两个函数的使用是紧密配合的,你要是自己设计其中一个,就要设计另外一个。在多数情况下,这两个函数是不用考虑的,直接使用它们的默认设计就可以了。但是在一些情况下,这两个...

    HashCode相同equals不同的2位字符集合算法

    在Java编程语言中,`hashCode()` 和 `equals()` 是两个非常重要的方法,它们主要用于对象的比较和哈希表(如HashMap)的操作。标题提到的"HashCode相同equals不同的2位字符集合算法"涉及到的是一个特定场景:两个...

    java中hashcode()和equals()的详解.docx

    在Java编程语言中,`hashCode()`与`equals()`方法是非常重要的概念,它们不仅对于深入理解Java内存管理至关重要,也是实现自定义类的关键部分之一。本文将详细介绍这两个方法的工作原理、使用场景以及在Java集合框架...

    深入理解Java中HashCode方法

    同时,Java还提供了一些工具类和方法来帮助开发者实现hashCode方法,例如,Guava库中的Hashing类,它提供了多种hashCode算法,例如,MD5、SHA-1等。 Java中的hashCode方法是非常重要的,它直接影响着对象的比较和...

    set接口经常用的hashCode和equals方法详解

    ### set接口中hashCode和equals...在Java中,正确实现`hashCode`和`equals`方法对于确保`Set`接口的有效性和高性能至关重要。开发人员需要仔细设计这两个方法,以满足`Set`接口的要求,并考虑到性能和一致性等方面。

    javahashcode()和equals()和==的介绍和区别.pdf

    在Java编程中,`hashCode()`、`equals()`以及`==`是三个经常被提及的概念,它们在处理对象的比较和存储时起着关键作用。本文将深入探讨这三个概念的介绍、区别以及它们在Java对象比较中的应用。 首先,`hashCode()`...

    JAVA_高级特性(hashCode,clone,比较器,Class反射,序列化)

    ### Java 高级特性详解 #### 一、`hashCode` ...正确地重写 `equals` 和 `hashCode` 方法、使用 `Comparator` 进行排序、利用反射机制和序列化技术,以及实现 `clone` 方法都是开发高质量 Java 应用程序的重要技能。

    面试官瞬间就饱了,重写equals函数,需要重写hashCode函数吗?

    在Java编程语言中,`equals()` 和 `hashCode()` 方法是对象的基本组成部分,它们与对象的比较和哈希表(如 `HashMap`)的操作密切相关。在面试中,面试官提出的问题直指这两个方法的重要关联。 首先,`equals()` ...

    java equals函数用法详解

    在Java编程语言中,`equals()` 方法是一个关键的成员函数,它主要用于比较对象的值是否相等。这个方法源自于 `Object` 类,是所有其他类的基类。默认情况下,`equals()` 方法的行为与 `==` 运算符相同,即比较两个...

    重写equals方法

    在采用哈希算法的集合中,hashCode 方法和 equals 方法是紧密相关的。hashCode 方法用于计算对象的哈希值,而 equals 方法用于判断两个对象是否相等。如果两个对象的哈希值相同,那么它们也应该是相等的,反之亦然。...

    hash表和hashCode1

    哈希表,又称散列表,是...总的来说,哈希表通过高效的散列函数和冲突解决策略实现了快速的数据存取,而hashCode()方法则是这一过程中的关键一环,它与equals()方法协同工作,确保了对象在散列集合中的正确定位和比较。

    浅谈Java中的hashcode方法(推荐)

    在Java编程语言中,`hashCode()`方法是`Object`类的一个重要成员,它用于生成对象的哈希码,这个哈希码是一个整数,通常用于优化基于哈希的集合操作,如`HashSet`、`HashMap`和`HashTable`。这些集合依赖于`hashCode...

    java HashMap原理分析

    Java HashMap是一种基于哈希表的数据结构,它的存储原理是通过将Key-Value对存储在一个数组中,每个数组元素是一个链表,链表中的每个元素是一个Entry对象,Entry对象包含了Key、Value和指向下一个Entry对象的引用。...

    详解Java中用于查找对象哈希码值的hashCode()函数

    在Java编程语言中,`hashCode()`函数是一个非常关键的方法,特别是在使用哈希数据结构如HashMap、HashSet和Hashtable时。这个函数的主要目的是为了高效地定位对象在哈希表中的位置。当我们谈论哈希码,实际上是在...

    利用反射绕过编译器和hashcode高级应用

    1. 访问私有成员:在Java中,编译器通常会阻止对私有成员的直接访问。然而,通过反射,我们可以使用`java.lang.reflect.Field`和`java.lang.reflect.Method`类来获取并操作这些私有成员。例如,`Field.setAccessible...

Global site tag (gtag.js) - Google Analytics