In Java, arrays are objects and support object methods such as Object.equals(). However, arrays do not support any methods besides those provided by Object. Consequently, using Object.equals() on any array compares only array references, not their contents. Programmers who wish to compare the contents of two arrays must use the static two-argument Arrays.equals() method. This method considers two arrays equivalent if both arrays contain the same number of elements, and all corresponding pairs of elements in the two arrays are equivalent, according to Object.equals(). In other words, two arrays are equal if they contain equivalent elements in the same order. To test for reference equality, use the reference equality operators, == and !=.  

Because the effect of using Object.equals() to compare two arrays is often misconstrued as content equality, and because a better alternative exists in the use of reference equality operators, the use of the Object.equals() method to compare two arrays is disallowed.

Noncompliant Code Example

This noncompliant code example uses the Object.equals() method to compare two arrays:

int[] arr1 = new int[20]; // Initialized to 0
int[] arr2 = new int[20]; // Initialized to 0
System.out.println(arr1.equals(arr2)); // Prints false

Compliant Solution

This compliant solution compares the content of two arrays using the two-argument Arrays.equals() method:

int[] arr1 = new int[20]; // Initialized to 0
int[] arr2 = new int[20]; // Initialized to 0
System.out.println(Arrays.equals(arr1, arr2)); // Prints true

Compliant Solution

This compliant solution compares the array references using the reference equality operators ==:

int[] arr1 = new int[20]; // Initialized to 0
int[] arr2 = new int[20]; // Initialized to 0
System.out.println(arr1 == arr2); // Prints false 

Risk Assessment

Using the equals() method or relational operators with the intention of comparing array contents produces incorrect results, which can lead to vulnerabilities.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

EXP02-J

Low

Likely

Low

P9

L2

Automated Detection

Static detection of calls to Object.equals() is straightforward. However, it is not always possible to statically resolve the class of a method invocation's target. Consequently, it may not always be possible to determine when Object.equals() is invoked for an array type.

Tool
Version
Checker
Description
CodeSonar
8.1p0

JAVA.COMPARE.EQ
JAVA.COMPARE.EQARRAY

Should Use equals() Instead of == (Java)
equals on Array (Java)

Coverity7.5

BAD_EQ
FB.EQ_ABSTRACT_SELF
FB.EQ_ALWAYS_FALSE
FB.EQ_ALWAYS_TRUE
FB.EQ_CHECK_FOR_OPERAND_NOT_ COMPATIBLE_WITH_THIS
FB.EQ_COMPARETO_USE_OBJECT_ EQUALS
FB.EQ_COMPARING_CLASS_NAMES
FB.EQ_DOESNT_OVERRIDE_EQUALS
FB.EQ_DONT_DEFINE_EQUALS_ FOR_ENUM
FB.EQ_GETCLASS_AND_CLASS_ CONSTANT
FB.EQ_OTHER_NO_OBJECT
FB.EQ_OTHER_USE_OBJECT
FB.EQ_OVERRIDING_EQUALS_ NOT_SYMMETRIC
FB.EQ_SELF_NO_OBJECT
FB.EQ_SELF_USE_OBJECT
FB.EQ_UNUSUAL

Implemented
Parasoft Jtest
2023.1
CERT.EXP02.UEICDo not use '==' or '!=' to compare objects
SonarQube
9.9
S2159Silly equality checks should not be made

Related Guidelines

MITRE CWE

CWE-595, Comparison of Object References Instead of Object Contents

Bibliography





9 Comments

  1. This rule appears to suggest that any use of the equals() method on Array objects should be diagnosed. Is this what we were after?

    1. Yes. I suppose there are cases where you do want to use == on two Array objects, to see if they are references to the same object. While such code could be legit, I'd want the code to have a comment saying somewhere that this usage (over Arrays.equals()) is not an accident.

  2. Does the Coverity Prevent Version 5.0 BAD_EQflag use of the Object.equals() method to compare two arrays?

    1. I think the answer to your question is 'No'. It is a statistical checker, so it will flag code where you do one type of equality lots and the other a little, and it thinks you're being inconsistent.

      Reference: (not sure this is the authoritative) https://lhcb-coverity.cern.ch:8443/docs/checker_ref.html#static_java_checker_BAD_EQ

  3. automated detection section says

    Static detection of calls to Array.equals(...) is straightforward.

    it should be corrected as Object.equals(...).
    or, how about "one argument version of equals(...) ?
    I'm not sure if it can be described as "straightforward" to derive which method of the class is actually invoked...

    1. I've tweaked that sentence.

      The only difficulty in static analysis is determing which method actually gets invoked. It is easy to tell that a call to a non-static equals() method occurs. But since the actual type of object is known only at runtime, which equals() method is called is harder. Fortunately we don't care about that; we are satisfied with knowing that Object.equals() (or a subclass's non-static equals() method) was invoked.

      It's also easy to determine the declared type of an object. So we can see if Object.equals() was invoked on an array without running the program. We can also tell statically if == was used on an array. This rule prohibits both.

      1. I think part of the point of Yozo TODA's comment is that we don't need to statically detect Array.equals() because it is the compliant solution.  I'm going to edit accordingly.

  4. Automated detection section says:


    Static detection of calls to to Object.equals()


    Should it be:


    Static detection of calls to Object.equals()