读书人

对java中equals跟hashCode函数的一些理

发布时间: 2012-12-24 10:43:14 作者: rapoo

对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代码

  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。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。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. ????}??


??????

读书人网 >编程

热点推荐