java-training/src/HashCode.java
import java.util.HashSet;
import java.util.Set;

public class HashCode {
    private static class User {
        User(int id, String name, String email) {
            this.id = id;
            this.name = name;
            this.email = email;
        }

        private long id;
        private String name;
        private String email;

        @Override
        public boolean equals(Object o) {
            System.out.println("Equals Invoked");
            if (this == o) return true;
            if (o == null) return false;
            if (this.getClass() != o.getClass()) return false;
            User user = (User) o;
            return id == user.id
                    && (name.equals(user.name)
                    && email.equals(user.email));
        }

        // getters and setters here

        @Override
        public int hashCode() {
            System.out.println("HashCode Invoked");

            int hash = 7;
            hash = 31 * hash + (int) id;
            hash = 31 * hash + (name == null ? 0 : name.hashCode());
            hash = 31 * hash + (email == null ? 0 : email.hashCode());

            return hash;
        }

        @Override
        public String toString() {
            return "User{" +
                    "id=" + id +
                    ", name='" + name + '\'' +
                    ", email='" + email + '\'' +
                    '}';
        }
    }

    public static void main(String[] args) {
        Set<User> set = new HashSet<>();

//        Internal Set Implementation
//
//        user1  hash=122
//
//        user2  hash=345
//
//        0   1   2   3      4     ...         122              345
//       [ ] [ ] [ ] [ ] [ user3 ] ...    [user1, user4]  [user2, user 10]
//

//      hashCode helps to fastly weed out non-equal objects before comparing all the elements in the object
//      comparison is costly compared to computation
//      two objects have unequal hashcode => they are not equal
//      but if two object have equal hashcode => we need to check them with .equals()
//      two non-equal objects having equal hashcode is very rare

        set.add(new User(123, "sam", "envkt@example.com"));
        set.add(new User(123, "jon", "nnheo@example.com"));

        System.out.println("Started");

        System.out.println(set.contains(new User(123, "sam", "envkt@example.com")));

        System.out.println("Second check");

        System.out.println(set.contains(new User(123, "jon", "nnheo@example.com")));
    }
}
