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

Object的equals()重写

阅读更多
JDK1.6 API写道
public boolean equals(Object obj)指示其他某个对象是否与此对象“相等”。
equals 方法在非空对象引用上实现相等关系:

自反性:对于任何非空引用值 x,x.equals(x) 都应返回 true。
对称性:对于任何非空引用值 x 和 y,当且仅当 y.equals(x) 返回 true 时,x.equals(y) 才应返回 true。
传递性:对于任何非空引用值 x、y 和 z,如果 x.equals(y) 返回 true,并且 y.equals(z) 返回 true,那么 x.equals(z) 应返回 true。
一致性:对于任何非空引用值 x 和 y,多次调用 x.equals(y) 始终返回 true 或始终返回 false,前提是对象上 equals 比较中所用的信息没有被修改。
对于任何非空引用值 x,x.equals(null) 都应返回 false。
Object 类的 equals 方法实现对象上差别可能性最大的相等关系;即,对于任何非空引用值 x 和 y,当且仅当 x 和 y 引用同一个对象时,此方法才返回 true(x == y 具有值 true)。

注意:当此方法被重写时,通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。


参数:
obj - 要与之比较的引用对象。
返回:
如果此对象与 obj 参数相同,则返回 true;否则返回 false。
另请参见:
hashCode(), Hashtable

 我们先来看看Object中equals的实现:

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

 当且仅当两个对象是同一个时,equals才返回true,这个实现当然满足以上的自反性、对称性、传递性、一致性。然而在绝大多数情况下,这个默认实现都不好用,用户往往需要重写这个方法。一旦重写了这个方法,很可能潜在的破坏了以上约束,给程序带来潜在威胁。

 

看一个Effective java中给出的一个违反对称性的例子:

/**
 * Case-insensitive string. Case of the original string is preserved by
 * toString, but ignored in comparisons.
 */
public final class CaseInsensitiveString {
	private String s;

	public CaseInsensitiveString(String s) {
		if (s == null)
			throw new NullPointerException();
		this.s = s;
	}

	// Broken - violates symmetry!
	public boolean equals(Object o) {
		if (o instanceof CaseInsensitiveString)
			return s.equalsIgnoreCase(((CaseInsensitiveString) o).s);
		if (o instanceof String) // One-way interoperability!
			return s.equalsIgnoreCase((String) o);
		return false;
	}
	// Remainder omitted
}

 这个实现对于

CaseInsensitiveString cis = new CaseInsensitiveString("Polish");
String s = "polish"; 

 cis.equals(s) 为true,而s.equals(cis) 为false。如果出现下面的代码,结果是什么呢?

List list = new ArrayList();
list.add(cis);
list.contains(s) = ?

 到底list.contains(s)返回true还是false,这就说不清了。按照目前的JVM实现,这个是false。

一个可能的实现为:

	public boolean equals(Object o) {
		return o instanceof CaseInsensitiveString
				&& ((CaseInsensitiveString) o).s.equalsIgnoreCase(s);
	}

 

再看一个违反传递性的例子:

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;
	}

	// Broken - violates transitivity.
	public boolean equals(Object o) {
		if (!(o instanceof Point))
			return false;
		// If o is a normal Point, do a color-blind comparison
		if (!(o instanceof ColorPoint))
			return o.equals(this);
		// o is a ColorPoint; do a full comparison
		ColorPoint cp = (ColorPoint) o;
		return super.equals(o) && cp.color == color;
	}
}

 根据上面的实现

ColorPoint p1 = new ColorPoint(1, 2, Color.RED);
Point p2 = new Point(1, 2);
ColorPoint p3 = new ColorPoint(1, 2, Color.BLUE);

 p1.equals(p2) = ture && p2.equals(p3) = true,而p1.equals(p3) = false,原因很简单,在

if (!(o instanceof ColorPoint))
	return o.equals(this);

这里出了问题,当o为Point时,调用了Point的equals(),忽略了color属性,从而使得p1.equals(p2)&&p2.equals(p3),一个可能的实现为

// Adds an aspect without violating the equals contract
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;
}
/**
* Returns the point-view of this color point.
*/
public Point asPoint() {
return point;
}
public boolean equals(Object o) {
if (!(o instanceof ColorPoint))
return false;
ColorPoint cp = (ColorPoint)o;
return cp.point.equals(point) && cp.color.equals(color);
}
... // Remainder omitted
}

在重写扩展基类的equals方法时,最好放弃使用继承,而采取组成的方式,将基类作为一个成员属性,这样可以避免由继承带来的各种问题。There is simply no way to extend an instantiable class with a new aspect while preserving the compareTo contract。如果你想扩展一个已经实现了equals的类,不要去继承它,而是在类中使用一个它的实例对象作为成员。

 

 

接下来讲讲 == 操作符与equals()的关系。== 比较两个对象时,返回true意味着两个对象是同一个。在Object的默认实现中,== 与equals就是一回事,也就是

Object obj1, obj2;
obj1.equals(obj2) 与obj1 == obj2 是一样的效果,
但是要注意在obj1、obj2都为null时,前者会抛出异常而后者则返回true。

	Object obj1 = null, obj2 = null;
		if(obj1 == obj2){
			System.out.println("true");
		}else{
			System.out.println("false");
		}
		
		if(obj1.equals(obj2)){
			System.out.println("true");
		}else{
			System.out.println("false");
		}
	}

   输出为:

写道
true
Exception in thread "main" java.lang.NullPointerException

 

参考文档:

1,《Efficient Java》 Joshua Bloch

2, J2sk 6.0 API

 

分享到:
评论

相关推荐

    重写equals方法

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

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

    在Java编程语言中,`equals()` 和 `hashCode()` 方法是Object类中的两个核心方法,所有类都默认继承自Object类。这两个方法在处理对象比较和集合操作时起着至关重要的作用。当我们创建自定义类并需要对对象进行精确...

    重写toString和equals方法

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

    equals方法的重写.docx

    // 重写object的equals方法 public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (this.getClass() != obj.getClass()) return false; Students other = ...

    C# Equals 和 GetHashCode 方法重写

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

    Java_重写equals()和hashCode()

    首先,`equals()` 方法是Object类中的一个基础方法,用于比较两个对象是否相等。默认情况下,它比较的是对象的内存地址,也就是引用是否相同。但在实际开发中,我们往往需要根据对象的内容来判断它们是否相等,这时...

    winform 重写Equals源码

    1. **使用`override`关键字**:在自定义类中,使用`override`关键字重写基类`Object`的`Equals`方法。 ```csharp public override bool Equals(object obj) ``` 2. **类型检查**:在`Equals`方法内部,首先检查...

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

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

    equals与hashCode在实际开发中的重写写法

    这两个方法通常与`Object`类中的默认实现相关联,但为了在实际开发中实现正确的对象比较和哈希表操作,我们往往需要重写它们。以下是对这两个方法的详细解释以及在实际开发中的应用。 `equals()` 方法: `equals()`...

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

    在Java编程中,`equals()` 和 `hashCode()` 方法是Object类中的两个重要方法,它们在处理对象相等性以及在哈希表(如HashSet、HashMap)中起到关键作用。当自定义类时,有时需要根据业务逻辑重写这两个方法以满足...

    关于Object中equals方法和hashCode方法判断的分析

    "关于Object中equals方法和hashCode方法判断的分析" 在 Java 中,Object 类提供了两个重要的方法:equals 方法和 hashCode 方法。这两个方法都是用于比较两个对象是否相等的,但它们的实现机理和作用域却有所不同。...

    ==代替Object#equals() - 加速在容器类中搜索元素速度的可能性

    对于自定义对象,我们通常需要重写`equals()`和`hashCode()`方法,以确保根据对象的属性进行比较,而不仅仅是引用。这在处理大量数据时尤其重要,因为正确实现这些方法可以显著提高容器(如ArrayList、HashSet、...

    方法重写equals和多态

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

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

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

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

    如果我们只重写了 `equals()` 来比较姓名和年龄,而没有重写 `hashCode()`,那么即使两个 `Person` 实例具有相同的姓名和年龄,它们在哈希表中的位置也可能不同,导致不必要的比较和潜在的性能问题。 总结来说,...

    Java Object类认识

    - 在重写`equals()`时,通常也需重写`hashCode()`,以保持两个方法的一致性,遵循equals和hashCode约定,确保当两个对象相等时,它们的哈希码也应该相等。 总结来说,理解`Object`类及其提供的方法是Java开发的基础...

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

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

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

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

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

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

    C#使用Equals()方法比较两个对象是否相等的方法

    `Equals()`方法是Object类的一个成员,因此所有C#类都默认继承了这个方法。然而,对于自定义类,`Equals()`方法的行为可能需要根据具体需求进行重写,以实现更加精确的比较逻辑。 首先,我们来看一下基本类型的`...

Global site tag (gtag.js) - Google Analytics