具有反射的 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 让我有点担心,但鉴于该方法首先检查 thisanObject 是否相同 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。试试吧!