Apache EqualsBuilder.reflectionEquals判定父子类相等是否符合equals规范?
Short answer: Absolutely not — this violates the core contracts of Java's equals() method, making it incorrect behavior for a proper equals() implementation.
Let’s break this down using your examples and Java’s official equals() conventions:
First, the Java equals() Contract Rules Matter
From the Object class specification, two critical rules are being broken here:
- Symmetry: If
a.equals(b)returnstrue, thenb.equals(a)must also returntrue. In your test,A().equals(B())might betrueviaEqualsBuilder, butB().equals(A())would almost certainly returnfalse(especially if B has its ownequals()implementation or uses IDE-generated logic). This breaks symmetry entirely. - Consistency with class identity: For most non-extensible classes (the vast majority of cases),
equals()should only returntrueif both objects are instances of the exact same class. UsinggetClass() != o.getClass()(like IDEA's generated code does) enforces this, which prevents the parent/child equality mismatch you’re seeing.
Why Does EqualsBuilder.reflectionEquals() Do This?
Apache Commons' EqualsBuilder is designed for convenient property-by-property comparison via reflection, not strictly adhering to the equals() contract by default. The default reflectionEquals() method only checks the values of shared accessible properties between the two objects — it doesn’t verify that the objects are of the same class.
Even when you use the overload reflectionEquals(new A(), new B(), false, B.class), the excludeClass parameter just stops the comparison at the specified superclass (instead of going all the way to Object), it still doesn’t add a strict class equality check.
IDE-Generated equals() Is Correct for Most Cases
The code IDEA generates follows standard best practices:
@Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; A a = (A) o; return x == a.x; }
By checking getClass() != o.getClass(), it ensures that only instances of the exact same class can be equal. This avoids the symmetry problem and aligns with how most developers expect equals() to behave.
How to Fix EqualsBuilder to Follow the Contract
If you want to use EqualsBuilder for convenience but still comply with equals() rules, add an explicit class check first:
@Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; MyClass that = (MyClass) o; return new EqualsBuilder() .append(this.x, that.x) // Add other properties here .isEquals(); }
This way you get the simplicity of EqualsBuilder without violating the equals() contract.
内容的提问来源于stack exchange,提问作者cahen

