我是靠谱客的博主 活力鸡翅,最近开发中收集的这篇文章主要介绍覆盖equals方法——Object类——JavaObject:所有类的超类,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

Object:所有类的超类

  • 尽管 O b j e c t Object Object类是一个具体类,但设计它的主要目的是为了拓展。
  • 它的所有非 f i n a l final final方法(equals、hashCode、toString、clone、finalize)都有明确的通用约定
  • 任何一个类,它在覆盖这些方法的时候,都有责任遵循这些通用约定,如果不能做到这一点,其他依赖于这些约定的类就无法结合该类一起正常工作。
  • 以下介绍覆盖 e q u a l s equals equals方法时的通用约定

e q u a l s 方 法 equals方法 equals

  • O b j e c t Object Object类中的 e q u a l s equals equals方法用于检测一个对象是否等于另一个对象,这个方法将判断两个对象是否具有相同的引用。对于大多数类来说,这种比较并没有什么意义。
  • 我们常常需要检测两个对象的状态,如果两个对象的状态相等,那么就认为这两个对象是相等的。

覆盖 e q u a l s equals equals方法的建议

  1. 显示参数命名为 o t h e r O b j e c t otherObject otherObject,稍后需要将它转换为一个叫 o t h e r other other 的变量
  2. 检测 t h i s this this o t h e r O b j e c t otherObject otherObject 是否引用同一个对象:
    if(this == otherObject) return false;
  3. 检测 o t h e r O b j e c t otherObject otherObject 是否为空:
    if(otherObject == null) return false;
  4. 比较 t h i s this this o t h e r O b j e c t otherObject otherObject 是否同属于一个类(instanceof、getClass 稍后详细介绍
  5. o t h e r O b j e c t otherObject otherObject 转换为相应的类类型变量
    ClassName other = (ClassName) otherObject;
  6. 现在开始对所有 需要比较的域 进行比较(用 = = == == 比较基本类型域,用 O b j e c t s . e q u a l s Objects.equals Objects.equals 比较对象域)
    return field1 == other.field1 && Objects.equals(field2, other.field2) && ,,,;
  7. 如果在子类中重新定义equals方法,就要在其中包含调用:
    super.equals(other)

O b j e c t s . e q u a l s ( ) Objects.equals() Objects.equals()

  • static boolean equals(Object a, Object b)
  • 使用目的:防止NullPointerException异常,即,如果 a 为 null,则a.equals(b) 抛出异常
  • 功能:
    • 如果 a 和 b 都为 null,放回true
    • 如果其中之一为null,返回false
    • 否则返回: a . e q u a l s ( b ) a.equals(b) a.equals(b)

i n s t a n c e o f 关 键 字 instanceof关键字 instanceof

  • 下面是instanceof实现的伪代码
// obj instanceof T
boolean result;
if (obj == null) {
  result = false;
} else {
  try {
      T temp = (T) obj; // checkcast
      result = true;
  } catch (ClassCastException e) {
      result = false;
  }
}
  • 根据上述伪代码可知,instanceof 关键字判断:
    1. obj是否为null
    2. obj 是否为 T 的类的实例(即obj为T类的对象)
    3. obj是否为T 的子类的实例(即obj 为 继承自 T类的类的对象)
    4. obj是否为 T 接口类的实例(即T的接口,obj为实现该接口的类的实例)

j a v a . l o n g . C l a s s 类 java.long.Class类 java.long.Class

  • String getName() —— 返回这个类的名字
  • Class getSuperClass() —— 以 Class 对象的形式返回这个类的超类信息

g e t C l a s s ( ) 方 法 getClass()方法 getClass()

  • Class getClass() —— 该方法返回包含对象信息的类对象, 它的内容被封装在Class类中。

覆盖equals时的通用约定

  • 不需要覆盖equals的条件:

    1. 类的每个实例本质上都死唯一的,即,Object 提供的 equals 是合适的
    2. 类没有必要提供逻辑相等的测试功能
    3. 超类已经覆盖了equals,超类的equals 对子类 也正好适用
  • 如果我们需要给某个类赋予逻辑相等的概念,我们需要为该类覆盖equals方法。并遵循以下约定:

  • 自反性: x 非 null,则 x . e q u a l s ( x ) x.equals(x) x.equals(x) 返回 true

  • 对称性: x, y 非null, 则 x . e q u a l s ( y ) x.equals(y) x.equals(y) y . e q u a l s ( x ) y.equals(x) y.equals(x) 结果一样

  • 传递性: x . e q u a l s ( y ) x.equals(y) x.equals(y) y . e q u a l s ( z ) y.equals(z) y.equals(z) 为true,则 x . e q u a l s ( z ) x.equals(z) x.equals(z) 为 true

  • 一致性: 只要 x ,y比较时用到的值没有改变,则 x . e q u a l s ( y ) x.equals(y) x.equals(y) 不会改变

  • 非空性: x 非 null,则 x . e q u a l s ( n u l l ) x.equals(null) x.equals(null) 为 false

常见问题

  • 对称性问题(见例子)
  • 定义一个点类 Point, 属性x,y
class Point{
	private int x;
	private int y;
	@override
	public boolean equals(Object otherObject){
		if(this == otherObject) return true;
		
		if(otherObject == null) return false;

		if(!(otherObject instanceof Point)) return false;
		
		Point other = (Point) otherObject;
		return x == other.x && y == other.y;
	}
	,,,,//省略构造器,,,
}		
  • 现在拓展这个类 -> ColorPoint类, 新增属性color
class ColorPoint extends Point{
	private int color;
	@override
	public boolean equals(Object otherObject){
		if(!(otherObject instanceof ColorPoint))
			return false;
		return super.equals(otherObject) && ((ColorPoint)otherObject).color == color;
	}
	,,, // 省略构造器,,,
}
  • 那么(考虑下列比较结果)
Point x = new Point(x,y);
ColorPoint y = new ColorPoint(x,y,z)

// 考虑下列结果
x.equals(y);   // true

y.equals(x);   // false
  • 所以当拓展类是,我们可能会违反对称性(违反对称性会怎么样呢? 我也不知道,反正某些依恋于equals的对象方法不会正常工作),试考虑下列解决方案:
class ColorPoint extends Point{
	private int color;
	@override
	public boolean equals(Object otherObject){
		if(!(otherObject instanceof Point)
			return false;
		if(!(otherObject instanceof ColorPoint))
			return otherObject.equals(this);
		return super.equals(otherObject) && ((ColorPoint)otherObject).color == color;
	}
	,,, // 省略构造器,,,
}
  • 让ColorPoint.equals 进行 混合比较 ,也就是:当otherObject 为单纯Point类时,忽略颜色值
  • 但是,这样做可能违反了 传递性:
ColorPoint p1 = new ColorPoint(1, 2, Color.red);
Point p2 = new Point(1, 2);
ColorPooint p3 = new ColorPoint(1, 2, Color.green);

p1.equals(p2);   // true
p2.equals(p3);   // true
p1.equals(p3);   // false
  • 考虑上述代码比较结果。使用 instanceof 我们无法在拓展类时,即增加新的值组件,同时又保留equals约定 , (当然 继承类时 子类 与 父类 语义相同就不需要考虑这些问题)
  • 解决方案:getClass 测试 代替 instanceof 测试,考虑下列代码:
class ColorPoint extends Point{
	private int color;
	@override
	public boolean equals(Object otherObject){
		if(getClass() != otherObject.getClass())
			return false;
		return super.equals(otherObject) && ((ColorPoint)otherObject).color == color;
	}
	,,, // 省略构造器,,,
}


Point x = new Point(x,y);
ColorPoint y = new ColorPoint(x,y,z)

// 考虑下列结果
x.equals(y);   // false

y.equals(x);   // false

以上便是覆盖equals的详细内容,参考书籍:

  • Java核心技术 卷一
  • Effective Java
  • 覆盖equals的另一条原则:重写hashCode方法(下回分解)

最后

以上就是活力鸡翅为你收集整理的覆盖equals方法——Object类——JavaObject:所有类的超类的全部内容,希望文章能够帮你解决覆盖equals方法——Object类——JavaObject:所有类的超类所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(60)

评论列表共有 0 条评论

立即
投稿
返回
顶部