概述
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方法的建议
- 显示参数命名为 o t h e r O b j e c t otherObject otherObject,稍后需要将它转换为一个叫 o t h e r other other 的变量
- 检测
t
h
i
s
this
this 和
o
t
h
e
r
O
b
j
e
c
t
otherObject
otherObject 是否引用同一个对象:
if(this == otherObject) return false;
- 检测
o
t
h
e
r
O
b
j
e
c
t
otherObject
otherObject 是否为空:
if(otherObject == null) return false;
- 比较 t h i s this this 和 o t h e r O b j e c t otherObject otherObject 是否同属于一个类(instanceof、getClass 稍后详细介绍)
- 将
o
t
h
e
r
O
b
j
e
c
t
otherObject
otherObject 转换为相应的类类型变量
ClassName other = (ClassName) otherObject;
- 现在开始对所有 需要比较的域 进行比较(用
=
=
==
== 比较基本类型域,用
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) && ,,,;
- 如果在子类中重新定义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 关键字判断:
- obj是否为null
- obj 是否为 T 的类的实例(即obj为T类的对象)
- obj是否为T 的子类的实例(即obj 为 继承自 T类的类的对象)
- 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的条件:
- 类的每个实例本质上都死唯一的,即,Object 提供的 equals 是合适的
- 类没有必要提供逻辑相等的测试功能
- 超类已经覆盖了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:所有类的超类所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复