`
dingjob
  • 浏览: 183643 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

《Effective Java》阅读体会之二--所有对象和类的通用方法(equals 注意事项)

阅读更多

本节论述了通用对象-java类默认的继承对象(Object)的方法和注意事项,同时也对具有类似特性的Comparable.compareTo()也进行了讲解。

 

一.覆盖equals时要遵守通用约定

 

 1.Object的equals如下:

public boolean equals(Object obj) {
	return (this == obj);
    }

 每个类只与自身相等,这个相等是指同一个对象。如果你的equals定义就是这样的,那是不需要覆盖的。

 

如下几种情况是不需要覆盖的(1)代表活动实体的类(thread等);(2)设计者认为不关心逻辑相等,例如java.util.Random类就没有实现equals (3)超类继承过来的行为,对于子类同样适用的情况,如AbstractSet等

(4)只有一个对象的值类,如Enum


2.要覆盖equals的情况

 (1). 类是私有的或包级私有的,防止被意外调用,需要做异常处理

@override
public boolean equals(Object o){
   throw new AssertionError();
}

 (2).普通的值类,如Integer等

 

3.覆盖equals需要遵守的约定

自反性,x.equals(x)

对称性

传递性

一致性 多次调用x.equals(y)必须一致的返回true或false

我们看违反了其中一条-对称性时会出现什么情况

一个实现了区分大小写的String类如下:

public final class CaseInsensitiveString{
    private final String s;
    @override
    public boolean equals(Object o){
        if(o instanceof CaseInsensitiveString){
            return s.equalsIgnoreCase((CaseInsensitiveString)o);
       }
        if(o instanceof String){
            return s.equalsIgnoreCase((String)o);
       }
    }
}

 乍一看,没有什么问题,

 

CaseInsensitiveString cis = new CaseInsensitiveString("Job");
Stringg s = "job";

 

cis .equals(s)返回的是true;而对于String类的方法是不区分大小写的,s .equals(cis)必然返回false,显然不满足自反性,假如你把cis放入ArrayList,由于ArrayList调用了如下方法,判断是否相等

public int indexOf(Object o) {
	if (o == null) {
	    for (int i = 0; i < size; i++)
		if (elementData[i]==null)
		    return i;
	} else {
	    for (int i = 0; i < size; i++)
		if (o.equals(elementData[i]))
		    return i;
	}
	return -1;
    }

 

也就是直接调用了Object的equals,这时候你调用list.contains(s);返回的是false,这个是个巧合,很有可能返回了true;

结论:当你违反了equals约定,当其它类(包含equals函数调用)操作你的这个对象时,鬼知道结果是什么。原因很简单,你们都各自定义了equals,又没有统一规范,就好比两个瞎子画像,永远不可能一样。

修改如上错误,只要去掉第二个case就可以了

if(o instanceof CaseInsensitiveString){
            return s.equalsIgnoreCase((CaseInsensitiveString)o);
       }

4.如何在使用继承关系增加新的属性时,依然保留equals约定:

 

@override
public boolean equals(){
     if(0==null||o.getClass()!=getClass()){
         return false;
     }
     Point p = Point(o);// 强制转化为付费
   return p.x=x&&p.y=y;
}

 

5.java 库中的equals有些也是不符合标准的,要慎用,比如原来java.sql.TimeStamp中如下定义了equals

public boolean equals(Timestamp ts) {
	if (super.equals(ts)) {
	    if  (nanos == ts.nanos) {
		return true;
	    } else {
		return false;
	    }
	} else {
	    return false;
	}
    }

 违反了对称性,不能和Date对象用于同一个集合。
目前1.6.10版本已经做了修正,增加了一个方法,如下:

 public boolean equals(java.lang.Object ts) {
      if (ts instanceof Timestamp) {
	return this.equals((Timestamp)ts);
      } else {
	return false;
      }
    }

 

这样简单清晰多了。

 

6. 如何高效的写equals函数

实例如下:

public boolean equals(java.lang.Object phoneNumber) {
      if(this== phoneNumber){// 1.如equals比较耗费性能,先用==判断是
//否是对象的引用
           return true; 
      }
      if (ts instanceof phoneNumber) {// 2. instanceof 判断类型
	PhoneNumber pn=(PhoneNumber)phoneNumber; // 3. 转
//换类型
           return areaCode==null ||  (areaCode!=null&&areaCode.equals(pn.areaCode));
//4.关键域的比较,注意吧null情况,如果通常是相同对象引用,则这样快些
         }
//5.编写完成,注意检查对称性,传递性和一致性。
//6.覆盖equls时总要覆盖hashCode

@override
public hashCode(){
}

  

 

 

分享到:
评论

相关推荐

    Effective Java第三版1

    ### 第三章 对所有对象都通用的方法 这部分主要关注Java中的基本对象行为: 1. **equals方法**:正确覆写`equals`以满足等价关系,同时要遵循一致性和传递性原则。 2. **hashCode方法**:当覆写`equals`时,必须同时...

    Effective-Java-2nd-Edition-(May-2008).zip_effective java

    1. **类和对象的设计原则**:书中强调了设计良好的API的重要性,包括接口的使用、类的封装、以及如何正确使用final关键字来防止意外修改。 2. **重写equals()和hashCode()**:Bloch建议当重写equals()方法时,也应...

    类与对象-java实验报告

    通过本次实验,学生可以深化理解面向对象编程的核心概念,学习如何在实际问题中运用类和对象,以及如何通过类与类的关系组织代码结构。这将有助于提高学生的编程能力和软件设计能力,为后续的项目开发奠定坚实的基础...

    effective-java 配套代码

    6. **重写equals()和hashCode()方法(Overriding equals() and hashCode())**: 代码展示了如何正确实现这两个方法以遵循合同,尤其是在实现集合类时的注意事项。 7. **接口与抽象类(Interfaces vs Abstract ...

    effective java 读书笔记

    《Effective Java》是Java开发领域的经典著作,作者Joshua Bloch深入浅出地阐述了编写高效、健壮的Java代码的技巧和最佳实践。以下是对该书部分内容的详细解释: 1. **产生和销毁对象** - Item1:静态工厂方法相比...

    计算机后端-Java-Java核心基础-第14章 面向对象06 14. 重写equals().avi

    计算机后端-Java-Java核心基础-第14章 面向对象06 14. 重写equals().avi

    重写equals方法

    在 Java 中,equals 方法是一个非常重要的方法,它用于判断两个对象是否相等,而不是判断两个对象的引用是否相同。在 Object 基类中,equals 方法的实现是使用“==”操作符来比较对象的引用,但是这并不满足实际需求...

    effectiveJava课件分享

    在面向对象编程中,封装是核心概念之一,它涉及到控制类和类成员(如字段和方法)的可见性。通常,我们应尽可能地限制类和成员的可访问性,以降低耦合度,提高安全性。例如,如果一个字段仅在类内部使用,那么将其...

    java中的==和equals()方法1

    在Java编程语言中,了解如何正确使用`==`和`equals()`方法是非常关键的,因为它们在比较对象和基本类型时有不同的行为。下面将详细解释这两个方法的工作原理、使用场景以及一些常见误区。 首先,`==`运算符主要用于...

    计算机后端-Java-Java核心基础-第14章 面向对象06 13. equals()的使用.avi

    计算机后端-Java-Java核心基础-第14章 面向对象06 13. equals()的使用.avi

    equals方法的重写.docx

    `equals`方法是Java语言中Object类的一个重要成员方法,其默认实现是比较两个对象的内存地址是否相同(即是否为同一个对象)。为了使对象之间能够基于内容进行比较,通常需要在具体的类中重写`equals`方法。 #### ...

    计算机后端-Java-Java核心基础-第14章 面向对象06 16. equals()练习1:代码实现.avi

    计算机后端-Java-Java核心基础-第14章 面向对象06 16. equals()练习1:代码实现.avi

    计算机后端-Java-Java核心基础-第14章 面向对象06 17. equals()练习2:代码实现.avi

    计算机后端-Java-Java核心基础-第14章 面向对象06 17. equals()练习2:代码实现.avi

    java代码-使用java解决实现Student类的equals重载函数的源代码

    java代码-使用java解决实现Student类的equals重载函数的源代码 ——学习参考资料:仅用于个人学习使用!

    Java中equals方法隐藏的陷阱

    在Java编程中,正确实现`equals`方法至关重要,它不仅影响对象的比较逻辑,还直接关系到集合类(如`HashSet`、`HashMap`等)的行为。本文将深入探讨Java中`equals`方法的一些常见陷阱,并提供相应的解决方案。 ####...

    计算机后端-Java-Java核心基础-第14章 面向对象06 15. 总结==与equals().avi

    计算机后端-Java-Java核心基础-第14章 面向对象06 15. 总结==与equals().avi

    java中hashcode()和equals()方法详解

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

    Java理论与实践:hashCode()和equals()方法

    本文介绍了Java语言不直接支持关联数组,可以使用任何对象作为一个索引的数组,但在根Object类中使用 hashCode()方法明确表示期望广泛使用HashMap。理想情况下基于散列的容器提供有效插入和有效检索;直接在对象模式...

Global site tag (gtag.js) - Google Analytics