具有反射的 Object.equals() 方法的广义覆盖的安全性
Safety of Generalized Override of Object.equals() Method With Reflection
我厌倦了必须为我的所有 classes 覆盖 Object.equals,所以我想出了这个覆盖方法,如果在所有 classes 中使用一个项目,似乎会产生预期的结果。
@Override
public boolean equals(Object anObject){
if (this == anObject) {
return true;
}
//same class?
if (anObject.getClass() == this.getClass()) {
Field[] fields = this.getClass().getFields();
boolean fieldsEqual = true;
for (Field field : fields) {
try {
fieldsEqual &=
field.get(anObject).equals(field.get(this));
} catch (IllegalAccessException e) { }
}
//if fields equal, objects are equal.
return fieldsEqual;
}
//not the same class, so the objects aren't equal
return false;
}
这里安全吗?未处理的 IllegalAccessException
让我有点担心,但鉴于该方法首先检查 this
和 anObject
是否相同 class,我认为这永远不会发生除非在运行时从 class 中动态删除或添加了一个字段。看起来这可能是一个非常方便的代码片段,如果它是安全的,除了那个例外。
Whosebug 的专业人士怎么看?
我不认为 try/catch 吞下 IllegalAccessException 是个好主意,这可能会导致您调试一个非常棘手的错误,我会在某处记录。
我通常使用 ApacheCommons equals method 作为 equals()。
这真是一个非常糟糕的主意。
请让 IDE 为您生成 hashCode()
和 equals()
,或者使用库,即 Apache Commons Lang EqualsBuilder,正如@Louis Wasserman 所建议的。
除了性能不佳和 NullPointerException
在字段为 null
时被抛出(如评论中所述),您的代码可能 运行 进入无限循环:
public static class Test {
static class ClassWithUnsafeEqualsMethod {
@Override
public boolean equals(Object anObject){
if (this == anObject) {
return true;
}
//same class?
if (anObject.getClass() == this.getClass()) {
Field[] fields = this.getClass().getFields();
boolean fieldsEqual = true;
for (Field field : fields) {
try {
fieldsEqual &=
field.get(anObject).equals(field.get(this));
} catch (IllegalAccessException e) { }
}
//if fields equal, objects are equal.
return fieldsEqual;
}
//not the same class, so the objects aren't equal
return false;
}
}
static class A extends ClassWithUnsafeEqualsMethod {
B fieldB;
}
static class B extends ClassWithUnsafeEqualsMethod {
A fieldA;
}
public static void main(String... args) {
A a1 = new A();
A a2 = new A();
B b1 = new B();
B b2 = new B();
a1.fieldB = b2;
b2.fieldA = a1;
a2.fieldB = b1;
b1.fieldA = a2;
System.out.println(a1.equals(a2));
}
}
你有一个很好的java.lang.WhosebugError
。试试吧!
我厌倦了必须为我的所有 classes 覆盖 Object.equals,所以我想出了这个覆盖方法,如果在所有 classes 中使用一个项目,似乎会产生预期的结果。
@Override
public boolean equals(Object anObject){
if (this == anObject) {
return true;
}
//same class?
if (anObject.getClass() == this.getClass()) {
Field[] fields = this.getClass().getFields();
boolean fieldsEqual = true;
for (Field field : fields) {
try {
fieldsEqual &=
field.get(anObject).equals(field.get(this));
} catch (IllegalAccessException e) { }
}
//if fields equal, objects are equal.
return fieldsEqual;
}
//not the same class, so the objects aren't equal
return false;
}
这里安全吗?未处理的 IllegalAccessException
让我有点担心,但鉴于该方法首先检查 this
和 anObject
是否相同 class,我认为这永远不会发生除非在运行时从 class 中动态删除或添加了一个字段。看起来这可能是一个非常方便的代码片段,如果它是安全的,除了那个例外。
Whosebug 的专业人士怎么看?
我不认为 try/catch 吞下 IllegalAccessException 是个好主意,这可能会导致您调试一个非常棘手的错误,我会在某处记录。
我通常使用 ApacheCommons equals method 作为 equals()。
这真是一个非常糟糕的主意。
请让 IDE 为您生成 hashCode()
和 equals()
,或者使用库,即 Apache Commons Lang EqualsBuilder,正如@Louis Wasserman 所建议的。
除了性能不佳和 NullPointerException
在字段为 null
时被抛出(如评论中所述),您的代码可能 运行 进入无限循环:
public static class Test {
static class ClassWithUnsafeEqualsMethod {
@Override
public boolean equals(Object anObject){
if (this == anObject) {
return true;
}
//same class?
if (anObject.getClass() == this.getClass()) {
Field[] fields = this.getClass().getFields();
boolean fieldsEqual = true;
for (Field field : fields) {
try {
fieldsEqual &=
field.get(anObject).equals(field.get(this));
} catch (IllegalAccessException e) { }
}
//if fields equal, objects are equal.
return fieldsEqual;
}
//not the same class, so the objects aren't equal
return false;
}
}
static class A extends ClassWithUnsafeEqualsMethod {
B fieldB;
}
static class B extends ClassWithUnsafeEqualsMethod {
A fieldA;
}
public static void main(String... args) {
A a1 = new A();
A a2 = new A();
B b1 = new B();
B b2 = new B();
a1.fieldB = b2;
b2.fieldA = a1;
a2.fieldB = b1;
b1.fieldA = a2;
System.out.println(a1.equals(a2));
}
}
你有一个很好的java.lang.WhosebugError
。试试吧!