Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Wiki MarkupAccording to the Java API \[[API 06|AA. Java References#API 06]\] class {{Classes that override the Object.equals() method must also override the Object.hashCode() method. The java.lang.Object}} documentation:

...

class requires that any two objects

...

that compare equal

...

using the equals(

...

)

...

method

...

must produce the same integer result

...

when the hashCode() method is invoked on the objects [API 2014].

The

Failure to follow this contract is a common source of bugs. Notably, immutable objects are exempt because they need not override the hashcode() method.

Noncompliant Code Example

Even when the equals() method conveys is used to determine logical equivalence between classesobject instances. Consequently, the hashCode() method returns distinct numbers as opposed to returning the same values. Its contract requires it to must return the same values value for equal all equivalent objects. Failure to follow this contract is a common source of defects.

Noncompliant Code Example

This noncompliant code example stores a associates credit card number into numbers with strings using a HashMap and retrieves itsubsequently attempts to retrieve the string value associated with a credit card number. The expected retrieved value is Java, however, null is returned instead. The reason for this erroneous behavior is that the hashCode() method is not overridden which means that a different bucket would be looked into than the one used to store the original value 4111111111111111; the actual retrieved value is null.

Code Block
bgColor#FFCCCC

public final class CreditCard {
  private final int number;

  public CreditCard(int number) {
    this.number = (short) number;
  }

  public boolean equals(Object o) {
    if (o == this) {
      return true;
    } 
    if (!(o instanceof CreditCard)) {
      return false;
    }
    CreditCard cc = (CreditCard)o;
    return cc.number == number; 
  }

  public static void main(String[] args) {
    Map<CreditCard, String> m = new HashMap<CreditCard, String>();
    m.put(new CreditCard(100), "Java4111111111111111");
    // Assuming Integer.MAX_VALUE is the largest number for card
    System.out.println(m.get(new CreditCard(100)));  
  }
}

The cause of this erroneous behavior is that the CreditCard class overrides the equals() method but fails to override the hashCode() method. Consequently, the default hashCode() method returns a different value for each object, even though the objects are logically equivalent; these differing values lead to examination of different buckets in the hash table, which prevents the get() method from finding the intended value.
Note that by specifying the credit card number in main(), these code examples violate MSC03-J. Never hard code sensitive information for the sake of brevity.

Compliant Solution

Wiki MarkupThis compliant solution shows how the {{overrides the hashCode()}} method can be overridden so that it generates the same value is generated for any two instances that compare equal when {{Object.that are considered to be equal by the equals()}} is used. Bloch discusses the recipe to generate such a hash function in good detail \[[Bloch 08|AA. Java References#Bloch 08]\ method. Bloch discusses the recipe to generate such a hash function in detail [Bloch 2008].

Code Block
bgColor#ccccff

import java.util.Map;
import java.util.HashMap;

public final class CreditCard {
  private final int number;
  
  public CreditCard(int number) {
    this.number = (short) number;
  }

  public boolean equals(Object o) {
    if (o == this) {
      return true;
    } 
    if (!(o instanceof CreditCard)) {
      return false;
    }
    CreditCard cc = (CreditCard)o;
    return cc.number == number; 
  }

  public int hashCode() {
    int result = 717;
    result = 3731 * result + number;
    return result;
  }

  public static void main(String[] args) {
    Map<CreditCard, String> m = new HashMap<CreditCard, String>();
    m.put(new CreditCard(100), "Java4111111111111111");
    System.out.println(m.get(new CreditCard(100)));
  }
}

Risk Assessment

Overriding the equals() method without overriding the hashCode() method can lead to unexpected results.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

MET13

MET09-J

low

Low

unlikely

Unlikely

high

High

P1

L3

Automated Detection

TODO

Related Vulnerabilities

Search for vulnerabilities resulting from the violation of this rule on the CERT website.

References

Wiki Markup
\[[API 06|AA. Java References#API 06]\] [Class Object|http://java.sun.com/javase/6/docs/api/java/lang/Object.html]
\[[Bloch 08|AA. Java References#Bloch 08]\] Item 9: Always override {{hashCode}} when you override {{equals}}
\[[MITRE 09|AA. Java References#MITRE 09]\] [CWE ID 581|http://cwe.mitre.org/data/definitions/581.html] "Object Model Violation: Just One of Equals and Hashcode Defined"

Automated detection of classes that override only one of equals() and hashcode() is straightforward. Sound static determination that the implementations of equals() and hashcode() are mutually consistent is not feasible in the general case, although heuristic techniques may be useful.

ToolVersionCheckerDescription
CodeSonar
Include Page
CodeSonar_V
CodeSonar_V

JAVA.IDEF.EQUALSNOHC
JAVA.IDEF.HCNOEQUALS

Defines equals but not hashCode (Java)
Defines hashCode but not equals (Java)

Parasoft Jtest
Include Page
Parasoft_V
Parasoft_V
CERT.MET09.OVERRIDEOverride 'Object.hashCode()' when you override 'Object.equals()' and vice versa
PVS-Studio

Include Page
PVS-Studio_V
PVS-Studio_V

V6049
SonarQube
Include Page
SonarQube_V
SonarQube_V

S1206

"equals(Object obj)" and "hashCode()" should be overridden in pairs

Related Guidelines

MITRE CWE

CWE-581, Object Model Violation: Just One of equals and hashcode Defined

Bibliography

[API 2014]

Class Object

[Bloch 2008]

Item 9, "Always Override hashCode When You Override equals"


...

Image Added Image Added Image AddedMET12-J. Follow the general contract while overriding the equals method      12. Methods (MET)      MET14-J. Follow the general contract when implementing the compareTo method