Back to Object Class, equals & hashCode
Q9Question 9 of 9

Why do == and equals() not compare array contents?

Key Concepts
  • == on arrays compares references (same object in memory?), not contents
  • Arrays do NOT override equals() – it uses Object.equals() which is ==
  • Use Arrays.equals(a, b) for content comparison of 1D arrays
  • Use Arrays.deepEquals(a, b) for content comparison of nested/2D arrays
  • Use Arrays.toString(a) for readable output – not a.toString() which gives [I@hex

Definition

Arrays do not override equals() or toString(). Use Arrays.equals() for content comparison and Arrays.toString() for readable output.

Array gotchas:

  • == compares references. Two different arrays with same elements: == is false.
  • equals() uses Object.equals(). Same as == because arrays do not override it.
  • Arrays.equals(a, b) compares element by element.
  • Arrays.deepEquals(a, b) compares nested arrays recursively.
  • a.toString() gives [I@1a2b3c (class + hash). Use Arrays.toString(a) for [1, 2, 3].

Two identical bank forms in different envelopes. == asks if they are the same envelope (no). Arrays.equals opens both envelopes and compares the contents (yes, identical).

Understanding the Concepts

The problem

JAVA
int[] a = {1, 2, 3};
int[] b = {1, 2, 3};

System.out.println(a == b);       // false (different objects)
System.out.println(a.equals(b));  // false (Object.equals = ==)
System.out.println(Arrays.equals(a, b));  // true (content comparison)

System.out.println(a.toString());          // [I@6d06d69c (useless)
System.out.println(Arrays.toString(a));    // [1, 2, 3] (readable)

For nested arrays

JAVA
int[][] x = {{1, 2}, {3, 4}};
int[][] y = {{1, 2}, {3, 4}};

System.out.println(Arrays.equals(x, y));      // false! Compares row references
System.out.println(Arrays.deepEquals(x, y));  // true! Compares element by element

System.out.println(Arrays.deepToString(x));   // [[1, 2], [3, 4]]

What should a senior engineer know?

  • List.equals() compares contents. List.of(1,2,3).equals(List.of(1,2,3)) is true. Arrays do not have this luxury.
  • In records with array fields, the auto-generated equals uses Arrays.equals – but only for 1D arrays. For nested arrays, you need to override.

What are common mistakes?

A common mistake is overriding equals() without overriding hashCode(), which breaks HashMap and HashSet behavior.

Wrong approach:

JAVA
package com.bank.model;

public class Account {
    private String accountId;

    // WRONG: overrides equals but not hashCode
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Account)) return false;
        return accountId.equals(((Account) o).accountId);
    }
    // Missing hashCode override!
}
JAVA
// This breaks HashMap lookups
Map<Account, String> map = new HashMap<>();
Account a1 = new Account("SAV2001");
map.put(a1, "Rajesh");
Account a2 = new Account("SAV2001");
System.out.println(map.get(a2));  // null! Different hashCode

Correct approach:

JAVA
package com.bank.model;

import java.util.Objects;

public class Account {
    private String accountId;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Account)) return false;
        return accountId.equals(((Account) o).accountId);
    }

    @Override
    public int hashCode() {
        return Objects.hash(accountId);
    }
}

Now both a1 and a2 produce the same hash code, so HashMap lookups work correctly.

What are the edge cases?

Edge cases can cause unexpected behavior in banking applications. Here are some to watch for.

JAVA
package com.bank.edge;

public class EdgeCaseDemo {
    public static void main(String[] args) {
        // Edge case 1: null handling
        String accountId = null;
        try {
            System.out.println(accountId.length());
        } catch (NullPointerException e) {
            System.out.println("Null account ID");
        }

        // Edge case 2: empty vs null
        String emptyId = "";
        System.out.println(emptyId.isEmpty());  // true
        System.out.println(emptyId == null);     // false

        // Edge case 3: boundary values
        java.math.BigDecimal zero = java.math.BigDecimal.ZERO;
        java.math.BigDecimal negativeBalance = new java.math.BigDecimal("-0.01");
        System.out.println(zero.compareTo(negativeBalance) > 0);  // true
    }
}
TEXT
Null account ID
true
false
true

Always test with null values, empty strings, boundary values, and negative amounts in banking applications.

What are common interview follow-up questions?

Interviewers often follow up with these related questions:

  • How does this concept apply to a high-throughput banking transaction system?
  • What are the performance implications in a production environment?
  • How would you debug issues related to this concept?
  • What tools would you use to monitor this in production?
  • How does this behave differently in Java 8 vs Java 17+?

When answering follow-up questions, always relate your answer back to practical experience. For example, at National Bank of India, Rajesh debugged a production issue related to this concept by using JFR recordings and heap dumps. Providing concrete examples from banking systems shows the interviewer that you understand both the theory and the practice.

Visual Overview

DIAGRAM
  int[] a = {1,2,3}, b = {1,2,3};

  a == b             → false (different objects)
  a.equals(b)        → false (Object.equals = ==)
  Arrays.equals(a,b) → true  (content comparison)

  a.toString()         → [I@hex (useless)
  Arrays.toString(a)   → [1, 2, 3] (readable)

  For 2D: Arrays.deepEquals, Arrays.deepToString

Key Takeaway

Arrays do not override equals() or toString(). Use Arrays.equals() for content comparison, Arrays.deepEquals() for nested arrays, and Arrays.toString() for readable output. Never use == or .equals() on arrays for content comparison.

One sentence to remember: arrays do not override equals – use Arrays.equals() for content and Arrays.toString() for display.

---

Share
Use ← → arrow keys to navigate