Home › Learn › Java › Exceptions, and the project

equals, hashCode, and Comparable

Lesson 39 of 40. Make your own classes compare, hash, and sort like built-in ones.

Two objects are equals only if the class says so; the inherited version compares identity, so two new Version(1, 2) are not equal until you override equals(Object other). Whenever you override equals, override hashCode the same way (Objects.hash(major, minor)), or HashSet and HashMap will not find your objects. Records do all of this for you, which is why they are the first choice for value types; a class needs it when it also carries behavior or mutable state.

Implementing Comparable<Version> with int compareTo(Version other) (negative, zero, or positive) lets Collections.sort and largest-style methods order your objects. Integer.compare(a, b) is the safe way to compare two numbers inside it.

@Override
public boolean equals(Object other) {
    if (!(other instanceof Version)) {
        return false;
    }
    Version v = (Version) other;
    return major == v.major && minor == v.minor;
}

@Override
public int hashCode() {
    return Objects.hash(major, minor);
}

Your task

Write class Version implements Comparable<Version> with int major and int minor, a constructor, equals and hashCode based on both numbers, toString() returning <major>.<minor>, and compareTo ordering by major and then minor.

Hint 1

See the example for equals and hashCode; toString returns major + "." + minor.

Hint 2

compareTo: if (major != other.major) return Integer.compare(major, other.major); return Integer.compare(minor, other.minor);

Show the solution
import java.util.*;

public class Main {
    public static void main(String[] args) {
        List<Version> versions = new ArrayList<>(List.of(new Version(2, 0), new Version(1, 10), new Version(1, 2)));
        Collections.sort(versions);
        System.out.println(versions);
    }
}

class Version implements Comparable<Version> {
    int major;
    int minor;

    Version(int major, int minor) {
        this.major = major;
        this.minor = minor;
    }

    @Override
    public boolean equals(Object other) {
        if (!(other instanceof Version)) {
            return false;
        }
        Version v = (Version) other;
        return major == v.major && minor == v.minor;
    }

    @Override
    public int hashCode() {
        return Objects.hash(major, minor);
    }

    @Override
    public String toString() {
        return major + "." + minor;
    }

    public int compareTo(Version other) {
        if (major != other.major) {
            return Integer.compare(major, other.major);
        }
        return Integer.compare(minor, other.minor);
    }
}

    Compiles with OpenJDK javac and TeaVM, both compiled to WebAssembly (7 MB download the first time, then cached), and runs in this tab; nothing is sent anywhere.