Skip to content

Equalities

Equalities#

Object equality determines whether two objects are considered "the same" based on specific criteria. This comparison can be based on object identity (reference equality) or content similarity (value equality).

Types of Equality#

Reference Equality: Are these the exact same object? (same memory location)

Value Equality: Do these objects have the same meaningful characteristics? (functionally equivalent)

Equality Concepts#

graph LR
    A[Object Equality] --> B[Reference Equality]
    A --> C[Value Equality]

    B --> D["Same memory location"]
    C --> E["Same meaningful properties"]

    style A fill:#e3f2fd
    style B fill:#ffcdd2
    style C fill:#c8e6c9

Implementation Requirements#

graph TD
    A[Implementing Equality] --> B[Override equals method]
    A --> C[Override hashCode method]
    A --> D[Define equality criteria]

    B --> E[Compare meaningful properties]
    C --> F[Generate consistent hash codes]
    D --> G[Decide what makes objects equal]

    style A fill:#fff3e0
    style B fill:#e8f5e8
    style C fill:#e8f5e8

Hash Collections Contract#

Hash-based collections like HashMap and HashSet use hash codes to quickly locate and store objects. For these collections to work correctly, there's a critical contract: if two objects are equal according to equals(), they must produce the same hash code.

This contract ensures that:

  • Equal objects are stored in the same hash bucket
  • Collections can efficiently find and retrieve objects
  • Duplicate objects are properly identified and handled
graph LR
    A[Hash Collections] --> B[HashMap, HashSet]
    B --> C[Requires consistent equals + hashCode]
    C --> D[Equal objects must have same hash]

    style A fill:#f3e5f5
    style C fill:#ffebee

The programmer defines what "equal" means for their objects. This decision affects how objects behave in collections and hash-based data structures. When two objects are equal, they must produce the same hash code to work correctly with hash collections.

Let's explore how different programming languages implement equality:

Override equals() and hashCode() methods. Equal objects must have the same hash code for hash collections.

public class Guitar {
    private String brand;
    private String model;

    public Guitar(String brand, String model) {
        this.brand = brand;
        this.model = model;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;
        Guitar guitar = (Guitar) obj;
        return Objects.equals(brand, guitar.brand) &&
               Objects.equals(model, guitar.model);
    }

    @Override
    public int hashCode() {
        return Objects.hash(brand, model);
    }
}

// Create instances of Guitar
Guitar guitar1 = new Guitar("Fender", "Stratocaster");
Guitar guitar2 = new Guitar("Fender", "Stratocaster");
Guitar guitar3 = new Guitar("Gibson", "Les Paul");

System.out.println(guitar1.equals(guitar2));  // Output: true
System.out.println(guitar1.equals(guitar3));  // Output: false

Override equals() and hashCode() functions. Uses == operator for value equality.

class Guitar(val brand: String, val model: String) {
    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (javaClass != other?.javaClass) return false

        other as Guitar

        return brand == other.brand &&
               model == other.model
    }

    override fun hashCode(): Int {
        return brand.hashCode() * 31 + model.hashCode()
    }
}

// Create instances of Guitar
val guitar1 = Guitar("Fender", "Stratocaster")
val guitar2 = Guitar("Fender", "Stratocaster")
val guitar3 = Guitar("Gibson", "Les Paul")

println(guitar1 == guitar2)  // Output: true
println(guitar1 == guitar3)  // Output: false

Implement custom equals() method to compare object properties.

class Guitar {
    brand: string;
    model: string;

    constructor(brand: string, model: string) {
        this.brand = brand;
        this.model = model;
    }

    equals(other: any): boolean {
        return this === other || (
            other instanceof Guitar &&
            this.brand === other.brand &&
            this.model === other.model
        );
    }
}

// Create instances of Guitar
const guitar1 = new Guitar("Fender", "Stratocaster");
const guitar2 = new Guitar("Fender", "Stratocaster");
const guitar3 = new Guitar("Gibson", "Les Paul");

console.log(guitar1.equals(guitar2));  // Output: true
console.log(guitar1.equals(guitar3));  // Output: false

Override the == operator and hashCode getter for equality comparison.

class Guitar {
    String brand;
    String model;

    Guitar(this.brand, this.model);

    @override
    bool operator ==(Object other) =>
        identical(this, other) ||
        other is Guitar &&
            runtimeType == other.runtimeType &&
            brand == other.brand &&
            model == other.model;

    @override
    int get hashCode => brand.hashCode ^ model.hashCode;
}

// Create instances of Guitar
Guitar guitar1 = Guitar("Fender", "Stratocaster");
Guitar guitar2 = Guitar("Fender", "Stratocaster");
Guitar guitar3 = Guitar("Gibson", "Les Paul");

print(guitar1 == guitar2);  // Output: true
print(guitar1 == guitar3);  // Output: false

Conform to Equatable protocol and implement the == function.

class Guitar: Equatable {
    var brand: String
    var model: String

    init(brand: String, model: String) {
        self.brand = brand
        self.model = model
    }

    static func ==(lhs: Guitar, rhs: Guitar) -> Bool {
        return lhs.brand == rhs.brand && lhs.model == rhs.model
    }
}

// Create instances of Guitar
let guitar1 = Guitar(brand: "Fender", model: "Stratocaster")
let guitar2 = Guitar(brand: "Fender", model: "Stratocaster")
let guitar3 = Guitar(brand: "Gibson", model: "Les Paul")

print(guitar1 == guitar2)  // Output: true
print(guitar1 == guitar3)  // Output: false

Override the __eq__ method to define equality comparison.

class Guitar:
    def __init__(self, brand, model):
        self.brand = brand
        self.model = model

    def __eq__(self, other):
        if not isinstance(other, Guitar):
            return False
        return self.brand == other.brand and self.model == other.model

# Create instances of Guitar
guitar1 = Guitar("Fender", "Stratocaster")
guitar2 = Guitar("Fender", "Stratocaster")
guitar3 = Guitar("Gibson", "Les Paul")

print(guitar1 == guitar2)  # Output: true
print(guitar1 == guitar3)  # Output: false