...
Unfortunately, in this case it is impossible to extend the Card
class by class by adding a value or field in the subclass while preserving the Java equals()
contract contract. This problem is not specific to the Card class but applies to any class hierarchy that can consider equal instances of distinct subclasses of some superclass. For such cases, use composition rather than inheritance to achieve the desired effect effect [Bloch 2008]. This compliant solution adopts this approach by adding a private card
field to the XCard
class and providing a public viewCard()
method.], [Liskov 1994], [Cline, C++ Super-FAQ]. It is fundamentally impossible to have a class that both allows arbitrary subclass extensions and permits an equals()
method that is reflexive, symmetric, and transitive, as is required by Object.equals()
. In the interests of consistency and security, we forgo arbitrary subclass extensions, and assume that {{Card.equals()}} may impose certain restrictions on its subclasses.
This compliant solution adopts this approach by adding a private card
field to the XCard
class and providing a public viewCard()
method.
Code Block | ||
---|---|---|
| ||
Code Block | ||
| ||
class XCard { private String type; private Card card; // Composition public XCard(int number, String type) { card = new Card(number); this.type = type; } public Card viewCard() { return card; } public boolean equals(Object o) { if (!(o instanceof XCard)) { return false; } XCard cp = (XCard)o; return cp.card.equals(card) && cp.type.equals(type); } public int hashCode() {/* ... */} public static void main(String[] args) { XCard p1 = new XCard(1, "type1"); Card p2 = new Card(1); XCard p3 = new XCard(1, "type2"); XCard p4 = new XCard(1, "type1"); System.out.println(p1.equals(p2)); // Prints false System.out.println(p2.equals(p3)); // Prints false System.out.println(p1.equals(p3)); // Prints false System.out.println(p1.equals(p4)); // Prints true } } |
...
Violating the general contract when overriding the equals()
method can lead to unexpected results.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
MET08-J | Low | Unlikely | Medium | P2 | L3 |
Automated Detection
Tool |
---|
FB.CORRECTNESS.OVERRIDING_EQUALS_NOT_SYMMETRIC
equals method overrides equals in superclass and may not be symmetric
Related Guidelines
Bibliography
Version | Checker | Description | |||||||
---|---|---|---|---|---|---|---|---|---|
CodeSonar |
| JAVA.COMPARE.CTO.ASSYM | Asymmetric compareTo (Java) | ||||||
Parasoft Jtest |
| CERT.MET08.EQREFL | Make sure implementation of Object.equals(Object) is reflexive | ||||||
SonarQube |
| S2162 | "equals" methods should be symmetric and work for subclasses |
Related Guidelines
Bibliography
[API 2014] | Class URI Class URL (method equals() ) |
Item 8, "Obey the General Contract When Overriding | |
[Cline, C++ Super-FAQ] | |
Section 9.2, "Overriding the | |
Chapter 3, "Classes, Strings, and Arrays," section "The Object Class (Equality)" | |
[Liskov 1994] | Liskov, B. H.; Wing, J. M. (November 1994). A behavioral notion of subtyping. ACM Trans. Program. Lang. Syst.16 (6). pp. 1811–1841. doi:10.1145/197320.197383. An updated version appeared as CMU technical report: Liskov, Barbara; Wing, Jeannette (July 1999). "Behavioral Subtyping Using Invariants and Constraints" (PS). |
URI
Class
URL
(method equals()
)Item 8, "Obey the General Contract When Overriding equals
"
Section 9.2, "Overriding the equals
Method"
[Sun 2006] | Determining If Two Keys Are Equal (JCA Reference Guide) |
"More Joy of Sets" |
...
...