`

equals()方法的重写

 
阅读更多

来自http://www.iteye.com/topic/269601的文章

 

一、为什么equals()方法要重写?

判断两个对象在逻辑上是否相等,如根据类的成员变量来判断两个类的实例是否相等,而继承Object中的equals方法只能判断两个引用变量是否是同一个对象。这样我们往往需要重写equals()方法。

我们向一个没有重复对象的集合中添加元素时,集合中存放的往往是对象,我们需要先判断集合中是否存在已知对象,这样就必须重写equals方法。

 

 

二、怎样重写equals()方法?

  • 重写equals方法的要求:
    1.自反性:对于任何非空引用x,x.equals(x)应该返回true。
    2.对称性:对于任何引用x和y,如果x.equals(y)返回true,那么y.equals(x)也应该返回true。
    3.传递性:对于任何引用x、y和z,如果x.equals(y)返回true,y.equals(z)返回true,那么x.equals(z)也应该返回true。
    4.一致性:如果x和y引用的对象没有发生变化,那么反复调用x.equals(y)应该返回同样的结果。
    5.非空性:对于任意非空引用x,x.equals(null)应该返回false。

格式:

public boolean equals(Object obj) {
    if(this == obj)
        return false;
    if(obj == null)
        return false;
    if(getClass() != obj.getClass() )
        return false;
    MyClass other = (MyClass)obj;
    if(str1 == null) {
         if(obj.str1 != null) {
              return false;
         }
    }else if (!str1.equals(other.str1) )
             return false;
     }
    if(var1 != other.var1)
        return false;
    return true;
}

 如果子类中增加了新特性,同时保留equals方法,这时比较复杂。

 

 

 

接下来我们通过实例来理解上面的约定。我们首先以一个简单的非可变的二维点类作为开始:
public class Point{
  private final int x;
  private final int y;
  public Point(int x, int y){
    this.x = x;
    this.y = y;
  }

  public boolean equals(Object o){
    if(!(o instanceof Point))
      return false;
    Point p = (Point)o;
      return p.x == x && p.y == y;
  }

}


假设你想要扩展这个类,为一个点增加颜色信息:
public class ColorPoint extends Point{
  private Color color;
  public ColorPoint(int x, int y, Color color){
    super(x, y);
    this.color = color;
  }

  //override equasl()

  public boolean equals(Object o){
    if(!(o instanceof ColorPoint))
     return false;
    ColorPoint cp = (ColorPoint)o;
    return super.equals(o) && cp.color==color;
  }
}


  我们重写了equals方法,只有当实参是另一个有色点,并且具有同样的位置和颜色的时候,它才返回true。可这个方法的问题在于,你在比较一个普通点和一个有色点,以及反过来的情形的时候,可能会得到不同的结果:
public static void main(String[] args){
  Point p = new Point(1, 2);
  ColorPoint cp = new ColorPoint(1, 2, Color.RED);
  System.out.println(p.equals(cp));
  System.out.println(cp.eqauls(p));
}

运行结果:
true  
false
这样的结果显然违反了对称性,你可以做这样的尝试来修正这个问题:让ColorPoint.equals在进行混合比较的时候忽略颜色信息:
public boolean equals(Object o){
  if(!(o instanceof Point))
    return false;
  //如果o是一个普通点,就忽略颜色信息
  if(!(o instanceof ColorPoint))
    return o.equals(this);
  //如果o是一个有色点,就做完整的比较
  ColorPoint cp = (ColorPoint)o;
  return super.equals(o) && cp.color==color;
}

这种方法的结果会怎样呢?让我们先来测试一下:
public static void main(String[] args){
  ColorPoint p1 = new ColorPoint(1, 2, Color.RED);
  Point p2 = new Point(1, 2);
  ColorPoint p3 = new ColorPoint(1, 2, Color.BLUE);
  System.out.println(p1.equals(p2));
  System.out.println(p2.equals(p1));
  System.out.println(p2.equals(p3));
  System.out.println(p1.eqauls(p3));
}

运行结果:
true
true
true
false

  这种方法确实提供了对称性,但是却牺牲了传递性(按照约定,p1.equals(p2)p2.eqauals(p3)都返回truep1.equals(p3)也应返回true)。要怎么解决呢?

 

事实上,这是面向对象语言中关于等价关系的一个基本问题。要想在扩展一个可实例化的类的同时,既要增加新的特征,同时还要保留equals约定,没有一个简单的办法可以做到这一点。新的解决办法就是不再让ColorPoint扩展Point,而是在ColorPoint中加入一个私有的Point域,以及一个公有的视图(view)方法
public class ColorPoint{
  private Point point;
  private Color color;
  public ColorPoint(int x, int y, Color color){
    point = new Point(x, y);
    this.color = color;
  }

  //返回一个与该有色点在同一位置上的普通Point对象
  public Point asPoint(){
    return point;
  }

  public boolean equals(Object o){
    if(o == this)
     return true;
    if(!(o instanceof ColorPoint))
     return false;
    ColorPoint cp = (ColorPoint)o;
    return cp.point.equals(point)&&
             cp.color.equals(color);

  }
}

  还有另外一个解决的办法就是把Point设计成一个抽象的类(abstract class),这样你就可以在该抽象类的子类中增加新的特征,而不会违反equals约定。因为抽象类无法创建类的实例,那么前面所述的种种问题都不会发生。

重写equals方法的要点:
1.
使用==操作符检查实参是否为指向对象的一个引用

2.判断实参是否为null
3.
使用instanceof操作符检查实参是否为正确的类型
4.
把实参转换到正确的类型。
5.
对于该类中每一个关键域,检查实参中的域与当前对象中对应的域值是否匹
  配。对于既不是float也不是double类型的基本类型的域,可以使用==操作符
  进行比较;对于对象引用类型的域,可以递归地调用所引用的对象的equals方法;
  对于float类型的域,先使用Float.floatToIntBits转换成int类型的值,
  然后使用==操作符比较int类型的值;对于double类型的域,先使用
  Double.doubleToLongBits转换成long类型的值,然后使用==操作符比较
  long类型的值。
6.
当你编写完成了equals方法之后,应该问自己三个问题:它是否是对称的、传
  递的、一致的?(其他两个特性通常会自行满足)如果答案是否定的,那么请找到
  这些特性未能满足的原因,再修改equals方法的代码。

分享到:
评论

相关推荐

    重写equals方法

    例如,public boolean equals(Object o) 是一个正确的重写方法,而 public boolean equals(String o) 是一个重载方法,而不是重写方法。 equals 方法的实现 ------------------------- equals 方法的实现需要遵循...

    equals方法的重写.docx

    ### equals方法重写知识点解析 #### 一、equals方法简介 `equals`方法是Java语言中Object类的一个重要成员方法,其默认实现是比较两个对象的内存地址是否相同(即是否为同一个对象)。为了使对象之间能够基于内容...

    重写toString和equals方法

    Java 对象的toString和equals方法重写 在 Java 中,每个对象都继承自 Object 类,而 Object 类中定义了两个重要的方法:toString() 和 equals()。这两个方法都是非常重要的,它们分别用于对象的字符串表示和对象...

    重写equals和hashcode方法_equals_重写equals和hashcode方法_

    以下是对`equals()` 和 `hashCode()` 方法的详细解释及其重写的重要性。 **1. equals() 方法** `equals()` 方法用于比较两个对象是否相等。默认情况下,`equals()` 检查两个对象是否是同一个对象(即内存地址是否...

    C# Equals 和 GetHashCode 方法重写

    ### C# Equals 和 GetHashCode 方法重写 在C#编程中,`Equals` 和 `GetHashCode` 方法是非常重要的成员方法,它们对于确保对象的正确比较以及高效地存储和检索对象至关重要。这两个方法通常需要在自定义类中进行...

    Java中equals()方法重写实现代码

    Java中equals()方法重写实现代码详解 Java中equals()方法是Object类中定义的,作为所有类的父类,任何类都隐含地继承了该方法。 equals()方法用于判断两个对象的内容是否相同,如果没有重写该方法的类,需要重写该...

    Java重写equals同时需要重写hashCode的代码说明

    Java重写equals同时需要重写hashCode的代码说明,以及如何重写hashCode方法,此代码演示按照effective java书籍说明的重写思路。代码中演示了使用集合存储对象,并且对象作为key,需重写equals和hashCode.

    重写Java中的equals方法介绍

    Java中的equals方法重写介绍 Java中的equals方法是一个非常重要的方法,它用于判断两个对象是否相等。在Java中,所有的对象都继承自Object类,而Object类中有一个equals方法,该方法用于判断两个对象是否相等。但是...

    关于重写equals,hashcode以及compareTo方法!

    关于重写equals、hashcode以及compareTo方法! equals()方法是Object类中的一个方法,它用于比较两个对象是否相等。然而,它的默认实现是比较对象的引用(地址),而不是比较对象的实际内容。因此,在某些情况下,...

    重写hashCode()和equals()方法详细介绍

    如果我们重写了`equals()`方法来基于`name`和`age`判断两个`Coder`对象是否相等,那么我们也应该重写`hashCode()`,使具有相同`name`和`age`的`Coder`对象产生相同的哈希码。通常,`hashCode()`的实现会结合所有参与...

    方法重写equals和多态

    在Java编程语言中,"方法重写equals"和"多态"是两个核心概念,尤其对于面向对象的设计和实现至关重要。下面将详细解释这两个概念及其相互关系。 **方法重写equals()** 在Java中,`equals()`方法是Object类的一个...

    浅谈java 重写equals方法的种种坑

    关于 Java 中重写 equals 方法的种种坑 Java 中的 equals 方法是一种用于比较对象是否相等的方法,它是 Object 类中的一个方法。然而,重写 equals 方法并不是一件简单的事情,因为它需要遵守一些约定,否则可能会...

    为什么重写equals方法,还必须要重写hashcode方法

    为什么重写equals方法,还必须要重写hashcode方法

    Java_重写equals()和hashCode()

    但在实际开发中,我们往往需要根据对象的内容来判断它们是否相等,这时就需要重写 `equals()` 方法。重写时应遵循以下原则: 1. **自反性**:对于任何非null的引用值x,x.equals(x)应该返回true。 2. **对称性**:...

    winform 重写Equals源码

    在某些情况下,尤其是自定义控件或者业务实体类的设计中,我们可能需要重写`Equals`方法来实现特定的比较逻辑。下面我们将深入探讨WinForm中重写`Equals`方法的相关知识点。 首先,`Equals`方法是`Object`类中的一...

    3 Java中关于==和equal的区别 以及equals()方法重写

    Java 中关于 == 和 equal 的区别 及其 equals() 方法重写 Java 语言是 Sun 公司的开发成果,其主要特点是可以执行强,与平台的无关性使其实用性更强。但是 Java 中的 == 与 equal 是有区别的。 == 操作符是 Java ...

    为什么在重写 equals方法的同时必须重写 hashcode方法

    因此,为了保证对象在集合中的正确行为,当重写 `equals` 方法时,必须同时重写 `hashCode` 方法,确保相等的对象具有相同的哈希值。这样,集合可以正确地识别和处理相等的对象,避免数据一致性问题。同时,遵循这个...

    java中为何重写equals时必须重写hashCode方法详解

    当我们在自定义类中重写 `equals()` 方法时,通常也需要重写 `hashCode()` 方法,这是为了遵循一些重要的原则和保证数据结构如 `HashMap`、`HashSet` 的正确行为。 首先,`equals()` 方法用于比较两个对象是否相等...

    java中重写equals()方法的同时要重写hashcode()方法(详解)

    Java 中重写 equals() 方法的同时要重写 hashCode() 方法的重要性 在 Java 中,equals() 方法和 hashCode() 方法是两个紧密相关的方法,它们都是用于比较和标识对象的方法。equals() 方法用于比较两个对象的值是否...

    why在重写equals时还必须重写hashcode方法分享

    然而,在实际应用中,我们往往需要根据对象的内容来判断它们是否相等,因此在自定义类中重写 `equals()` 方法是常见的做法。例如,`String` 类就重写了 `equals()`,比较两个字符串的字符序列是否相同。 接着,我们...

Global site tag (gtag.js) - Google Analytics