我的 equals() 不满足 equals() 总合同的哪一部分
Which part of the equals() general contract does my equals() not satisfy
我是 java 的新手,我只是想了解 @Override
和 equals()
和 hashcode()
方法。
我知道要使 equals 方法正确,它必须是:
- 自反:
a.equals(a)
- 对称:
a.equals(b)
然后 b.equals(a)
- 传递:
a.equals(b) && b.equals(c)
然后 a.equals(c)
- 不为空:
! a.equals(null)
在编写我对 equals 方法的覆盖时,我正在努力确定我对上述哪些属性感到满意和不满意。
我知道eclipse可以为我生成这些,但是由于我还没有完全理解这个概念,写出来帮助我学习。
我已经写出了我认为正确的方法,但是当我检查 eclipse 生成的版本时,我似乎 'missing' 某些方面。
示例:
public class People {
private Name first; //Invariants --> !Null, !=last
private Name last; // !Null, !=first
private int age; // !Null, ! <=0
...
}
我写的:
public boolean equals(Object obj){
if (obj == null){
return false;
}
if (!(obj instanceof People)){
return false;
}
People other = (People) obj;
if (this.age != other.age){
return false;
}
if (! this.first.equals(other.first)){
return false;
}
if (! this.last.equals(other.last)){
return false;
}
return true;
}
vs eclipse 生成
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
People other = (People) obj;
if (first == null) {
if (other.first != null)
return false;
} else if (!first.equals(other.first))
return false;
if (age != other.age)
return false;
if (last == null) {
if (other.last != null)
return false;
} else if (!last.equals(other.last))
return false;
return true;
}
我失踪了:
if (this == obj)
return true;
if (getClass() != obj.getClass())
return false;
并且对于每个变量:
if (first == null) {
if (other.first != null)
return false;
} else if (!first.equals(other.first))
return false;
我不确定 getClass()
是什么,我的实现是否不正确?
我不认为你的实现有误,但有几点要注意:
if (this == obj)
return true;
是一个性能优化,它直接测试参考相等性和短路测试,其中a
是 a
.
if (getClass() != obj.getClass())
return false;
类似于您的 instanceof
调用,优化了空检查。其他调用似乎是空检查。
第一段代码:
if (this == obj)
return true;
如果您将对象引用与自身进行比较,这会提高性能。示例:a.equals(a);
.
第二段代码:
if (getClass() != obj.getClass())
return false;
这会比较被比较的引用的 class 是否与 this
的 class 相同。使用此方法与 instanceof
的区别在于,与子 class 相比,它的限制更为严格。示例:
public class Foo { }
public class Bar extends Foo { }
//...
Foo foo = new Bar();
System.out.println(foo instanceof Bar); //prints true
System.out.println(foo instanceof Foo); //prints true
Foo foo2 = new Foo();
System.out.println(foo.getClass() == foo2.getClass()); //prints false
你应该选择哪一个?方法没有好坏之分,这取决于你想要的设计。
第三段代码:
if (first == null) {
if (other.first != null)
return false;
} else if (!first.equals(other.first))
return false; //For each variable.
这只是对 class 中每个对象引用字段的空检查。请注意,如果 this.first
是 null
那么执行 this.first.equals(...)
将抛出 NullPointerException
.
你不需要写
if (obj == null){
return false;
}
if (!(obj instanceof People)){
return false;
}
因为 null
总是在 instanceof
检查中给出 false
。所以这些行可以简化为
if (!(obj instanceof People)){
return false;
}
至于你的主要问题是你的方法是否满足 equals()
方法的要求,严格来说答案是否定的,或者至少它可能是不可靠的。这是因为可以按如下方式扩展 class
public class SpecialPeople extends People {
// code omitted
@Override
public boolean equals(Object object) {
if (object == null || object.getClass() != getClass())
return false;
SpecialPeople other = (SpecialPeople) object;
return other.getAge() == getAge()
&& other.getFirst().equals(getFirst())
&& other.getLast().equals(getLast());
}
现在假设 a
是 People
的实例并且 b
是 SpecialPeople
的实例。还假设 a
和 b
具有相同的名字和年龄。然后
a.equals(b) == true // instanceof check succeeds
b.equals(a) == false // getClass() check fails
因此equals()
不对称!出于这个原因,如果您在 equals()
中使用 instanceof
而不是 getClass()
,您应该使 equals()
方法 final
或 class final
。
我是 java 的新手,我只是想了解 @Override
和 equals()
和 hashcode()
方法。
我知道要使 equals 方法正确,它必须是:
- 自反:
a.equals(a)
- 对称:
a.equals(b)
然后b.equals(a)
- 传递:
a.equals(b) && b.equals(c)
然后a.equals(c)
- 不为空:
! a.equals(null)
在编写我对 equals 方法的覆盖时,我正在努力确定我对上述哪些属性感到满意和不满意。
我知道eclipse可以为我生成这些,但是由于我还没有完全理解这个概念,写出来帮助我学习。
我已经写出了我认为正确的方法,但是当我检查 eclipse 生成的版本时,我似乎 'missing' 某些方面。
示例:
public class People {
private Name first; //Invariants --> !Null, !=last
private Name last; // !Null, !=first
private int age; // !Null, ! <=0
...
}
我写的:
public boolean equals(Object obj){
if (obj == null){
return false;
}
if (!(obj instanceof People)){
return false;
}
People other = (People) obj;
if (this.age != other.age){
return false;
}
if (! this.first.equals(other.first)){
return false;
}
if (! this.last.equals(other.last)){
return false;
}
return true;
}
vs eclipse 生成
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
People other = (People) obj;
if (first == null) {
if (other.first != null)
return false;
} else if (!first.equals(other.first))
return false;
if (age != other.age)
return false;
if (last == null) {
if (other.last != null)
return false;
} else if (!last.equals(other.last))
return false;
return true;
}
我失踪了:
if (this == obj) return true;
if (getClass() != obj.getClass()) return false;
并且对于每个变量:
if (first == null) { if (other.first != null) return false; } else if (!first.equals(other.first)) return false;
我不确定 getClass()
是什么,我的实现是否不正确?
我不认为你的实现有误,但有几点要注意:
if (this == obj) return true;
是一个性能优化,它直接测试参考相等性和短路测试,其中a
是 a
.
if (getClass() != obj.getClass()) return false;
类似于您的 instanceof
调用,优化了空检查。其他调用似乎是空检查。
第一段代码:
if (this == obj)
return true;
如果您将对象引用与自身进行比较,这会提高性能。示例:a.equals(a);
.
第二段代码:
if (getClass() != obj.getClass())
return false;
这会比较被比较的引用的 class 是否与 this
的 class 相同。使用此方法与 instanceof
的区别在于,与子 class 相比,它的限制更为严格。示例:
public class Foo { }
public class Bar extends Foo { }
//...
Foo foo = new Bar();
System.out.println(foo instanceof Bar); //prints true
System.out.println(foo instanceof Foo); //prints true
Foo foo2 = new Foo();
System.out.println(foo.getClass() == foo2.getClass()); //prints false
你应该选择哪一个?方法没有好坏之分,这取决于你想要的设计。
第三段代码:
if (first == null) {
if (other.first != null)
return false;
} else if (!first.equals(other.first))
return false; //For each variable.
这只是对 class 中每个对象引用字段的空检查。请注意,如果 this.first
是 null
那么执行 this.first.equals(...)
将抛出 NullPointerException
.
你不需要写
if (obj == null){
return false;
}
if (!(obj instanceof People)){
return false;
}
因为 null
总是在 instanceof
检查中给出 false
。所以这些行可以简化为
if (!(obj instanceof People)){
return false;
}
至于你的主要问题是你的方法是否满足 equals()
方法的要求,严格来说答案是否定的,或者至少它可能是不可靠的。这是因为可以按如下方式扩展 class
public class SpecialPeople extends People {
// code omitted
@Override
public boolean equals(Object object) {
if (object == null || object.getClass() != getClass())
return false;
SpecialPeople other = (SpecialPeople) object;
return other.getAge() == getAge()
&& other.getFirst().equals(getFirst())
&& other.getLast().equals(getLast());
}
现在假设 a
是 People
的实例并且 b
是 SpecialPeople
的实例。还假设 a
和 b
具有相同的名字和年龄。然后
a.equals(b) == true // instanceof check succeeds
b.equals(a) == false // getClass() check fails
因此equals()
不对称!出于这个原因,如果您在 equals()
中使用 instanceof
而不是 getClass()
,您应该使 equals()
方法 final
或 class final
。