Java 具有反射的Object.equals()方法的广义重写的安全性

Java 具有反射的Object.equals()方法的广义重写的安全性,java,reflection,overriding,Java,Reflection,Overriding,我已经厌倦了为我所有的类重写Object.equals,所以我提出了这个重写方法,如果在项目中的所有类中使用,它似乎会产生预期的结果 @Override public boolean equals(Object anObject){ if (this == anObject) { return true; } //same class? if (anObject.getClass() == this.getClass()) { Fi

我已经厌倦了为我所有的类重写Object.equals,所以我提出了这个重写方法,如果在项目中的所有类中使用,它似乎会产生预期的结果

@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
是否是同一个类,我认为除非在运行时从类中动态删除或添加字段,否则不会发生这种情况。如果可以安全地保存一个异常,那么这可能是一个非常方便的代码片段


StackOverflow的专业人士会怎么想?

我不认为尝试/捕获非法访问异常是一个好主意,这可能会导致您遇到一个非常棘手的bug进行调试,我会记录在某个地方


我通常使用for equals()。

我不认为try/catch吞下IllegaAccessException是一个好主意,这可能会导致您遇到一个非常棘手的bug进行调试,我会记录在某个地方


我通常使用for equals()。

我不认为try/catch吞下IllegaAccessException是一个好主意,这可能会导致您遇到一个非常棘手的bug进行调试,我会记录在某个地方


我通常使用for equals()。

我不认为try/catch吞下IllegaAccessException是一个好主意,这可能会导致您遇到一个非常棘手的bug进行调试,我会记录在某个地方


我通常使用for equals()。

这真是一个非常糟糕的主意

请让IDE为您生成
hashCode()
equals()
,或者按照@Louis Wasserman的建议使用一个库,即Apache Commons Lang

除了性能差和字段为
null
时抛出
NullPointerException
(如注释中所述)之外,您的代码可能会运行到无限循环中:

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.StackOverflowerError
。试试看

这真是一个非常糟糕的主意

请让IDE为您生成
hashCode()
equals()
,或者按照@Louis Wasserman的建议使用一个库,即Apache Commons Lang

除了性能差和字段为
null
时抛出
NullPointerException
(如注释中所述)之外,您的代码可能会运行到无限循环中:

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.StackOverflowerError
。试试看

这真是一个非常糟糕的主意

请让IDE为您生成
hashCode()
equals()
,或者按照@Louis Wasserman的建议使用一个库,即Apache Commons Lang

除了性能差和字段为
null
时抛出
NullPointerException
(如注释中所述)之外,您的代码可能会运行到无限循环中:

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.StackOverflowerError
。试试看

这真是一个非常糟糕的主意

请让IDE为您生成
hashCode()
equals()
,或者按照@Louis Wasserman的建议使用一个库,即Apache Commons Lang

除了性能差和字段为
null
时抛出
NullPointerException
(如注释中所述)之外,您的代码可能会运行到无限循环中:

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.StackOverflowerError
。试试看

你需要这样做吗?比较每个值会更安全、更快。否则,只要两个对象都有相同的字段(它们在比较
getClass()
之后就有相同的字段),我想您就不必担心了。看起来您重新发明了Apache的EqualsBuilder,但反射会带来巨大的运行时成本……您知道,自从Java 7以来,就有objects.equals,这将大大减少代码量。请不要懒惰,也不要为此使用反射。在海事组织,这不是一个好的解决办法。此外,大多数IDE都可以为您生成它们。毫无理由地使用反射是个坏主意。假设所有字段都是公共的是一个坏主意。在检查
null
之前访问任何未知对象的属性或方法是更糟糕的主意。我想不出有哪一种情况会通过比较对象上的所有字段来检查相等性。另外,hashcode方法必须与此兼容,但是如果字段数组没有在equals和hashcode中显式排序,那么情况就不会如此。然后,无论何时访问私有字段,都会抛出非法访问——我的所有字段都是私有的。那么,对于仅通过getter存在的派生字段会发生什么?更不用说表现了。你需要这样做吗?比较每个值会更安全、更快。否则,只要两个对象都有相同的字段(它们在比较
getClass()
之后就有相同的字段),我想您就不必担心了。看起来您重新发明了Apache的EqualsBuilder,但反射会带来巨大的运行时成本……您知道,自从Java 7以来,就有objects.equals,这将大大减少代码量。请不要懒惰,也不要为此使用反射。在海事组织,这不是一个好的解决办法。此外,大多数IDE都可以为您生成它们。毫无理由地使用反射是个坏主意。假设所有字段都是公共的是一个坏主意。在检查
null
之前访问任何未知对象的属性或方法是更糟糕的主意。我想不出有哪一种情况会通过比较对象上的所有字段来检查相等性。另外,hashcode方法必须与此兼容,但是如果字段数组没有在equals和hashcode中显式排序,那么情况就不会如此。然后,你会得到非法的空调