Introduction
hashCode() returns an integer hash value for an object. Used in hash-based collections like HashMap, HashSet.
Default Implementation
class Student {
String name;
int rollNo;
Student(String name, int rollNo) {
this.name = name;
this.rollNo = rollNo;
}
}
public class Main {
public static void main(String[] args) {
Student s1 = new Student("John", 101);
Student s2 = new Student("John", 101);
// Default hashCode() returns different values
System.out.println(s1.hashCode()); // e.g., 366712642
System.out.println(s2.hashCode()); // e.g., 1829164700
}
}
Why Override hashCode()?
For hash-based collections to work correctly.
import java.util.HashSet;
class Student {
String name;
int rollNo;
Student(String name, int rollNo) {
this.name = name;
this.rollNo = rollNo;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Student s = (Student) obj;
return rollNo == s.rollNo && name.equals(s.name);
}
// Without hashCode() override
}
public class Main {
public static void main(String[] args) {
HashSet<Student> set = new HashSet<>();
Student s1 = new Student("John", 101);
Student s2 = new Student("John", 101);
set.add(s1);
set.add(s2);
// Without hashCode(), both added (wrong!)
System.out.println(set.size()); // 2 (should be 1)
}
}
Overriding hashCode()
class Student {
String name;
int rollNo;
Student(String name, int rollNo) {
this.name = name;
this.rollNo = rollNo;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Student s = (Student) obj;
return rollNo == s.rollNo && name.equals(s.name);
}
@Override
public int hashCode() {
int result = name.hashCode();
result = 31 * result + rollNo;
return result;
}
}
public class Main {
public static void main(String[] args) {
Student s1 = new Student("John", 101);
Student s2 = new Student("John", 101);
System.out.println(s1.hashCode()); // Same
System.out.println(s2.hashCode()); // Same
System.out.println(s1.equals(s2)); // true
}
}
hashCode() Contract
3 Rules:
- Consistent: Same object → same hash (if not modified)
- Equals → Same hash: If
x.equals(y)is true, thenx.hashCode() == y.hashCode() - Not required reverse: Different objects CAN have same hash (collision allowed)
// Rule 1: Consistent
Student s = new Student("John", 101);
int hash1 = s.hashCode();
int hash2 = s.hashCode();
// hash1 == hash2 (must be same)
// Rule 2: equals → same hash
Student s1 = new Student("John", 101);
Student s2 = new Student("John", 101);
if (s1.equals(s2)) {
// s1.hashCode() == s2.hashCode() (must be true)
}
// Rule 3: Different objects can have same hash
Student s3 = new Student("Alice", 102);
Student s4 = new Student("Bob", 103);
// s3.hashCode() might equal s4.hashCode() (collision OK)
Simple hashCode() Formula
@Override
public int hashCode() {
int result = field1.hashCode(); // First field
result = 31 * result + field2.hashCode(); // Second field
result = 31 * result + primitiveField; // Primitive field
return result;
}
Why 31?
- Prime number
- Good distribution
- Efficient:
31 * x = (x << 5) - x
Examples for Different Types
Single Field:
class Person {
String name;
@Override
public int hashCode() {
return name.hashCode();
}
}
Multiple Fields:
class Person {
String name;
int age;
@Override
public int hashCode() {
int result = name.hashCode();
result = 31 * result + age;
return result;
}
}
With null Check:
class Person {
String name;
String city;
@Override
public int hashCode() {
int result = (name != null) ? name.hashCode() : 0;
result = 31 * result + ((city != null) ? city.hashCode() : 0);
return result;
}
}
Complete Example
import java.util.HashSet;
class Employee {
private String empId;
private String name;
private double salary;
Employee(String empId, String name, double salary) {
this.empId = empId;
this.name = name;
this.salary = salary;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Employee emp = (Employee) obj;
return empId.equals(emp.empId); // Compare by ID only
}
@Override
public int hashCode() {
return empId.hashCode(); // Hash based on ID only
}
@Override
public String toString() {
return "Employee[" + empId + ", " + name + ", $" + salary + "]";
}
}
public class Main {
public static void main(String[] args) {
HashSet<Employee> employees = new HashSet<>();
Employee e1 = new Employee("E001", "John", 50000);
Employee e2 = new Employee("E001", "John Updated", 55000);
Employee e3 = new Employee("E002", "Alice", 60000);
employees.add(e1);
employees.add(e2); // Same ID as e1, not added
employees.add(e3);
System.out.println("Set size: " + employees.size()); // 2
System.out.println("Contains e2: " + employees.contains(e2)); // true
for (Employee emp : employees) {
System.out.println(emp);
}
}
}
Using Objects.hash() (Java 7+)
Easier way to generate hashCode().
import java.util.Objects;
class Person {
String name;
int age;
String city;
@Override
public int hashCode() {
return Objects.hash(name, age, city);
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Person person = (Person) obj;
return age == person.age &&
Objects.equals(name, person.name) &&
Objects.equals(city, person.city);
}
}
HashMap Example
import java.util.HashMap;
class Student {
String name;
int rollNo;
Student(String name, int rollNo) {
this.name = name;
this.rollNo = rollNo;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Student s = (Student) obj;
return rollNo == s.rollNo && name.equals(s.name);
}
@Override
public int hashCode() {
return 31 * name.hashCode() + rollNo;
}
@Override
public String toString() {
return name + "(" + rollNo + ")";
}
}
public class Main {
public static void main(String[] args) {
HashMap<Student, String> grades = new HashMap<>();
Student s1 = new Student("John", 101);
Student s2 = new Student("Alice", 102);
grades.put(s1, "A");
grades.put(s2, "B");
// Lookup with equal object
Student s3 = new Student("John", 101); // Equal to s1
System.out.println("Grade: " + grades.get(s3)); // A
}
}
Common Mistakes
Mistake 1: Override equals() but not hashCode()
class Student {
String name;
int rollNo;
@Override
public boolean equals(Object obj) {
// ... implementation
}
// ✗ Missing hashCode() - breaks HashMap/HashSet
}
Mistake 2: Using Mutable Fields
class Student {
String name; // Mutable
@Override
public int hashCode() {
return name.hashCode();
}
}
HashSet<Student> set = new HashSet<>();
Student s = new Student("John");
set.add(s);
s.name = "Alice"; // ✗ Hash changed, object lost in set!
System.out.println(set.contains(s)); // false (can't find it!)
Mistake 3: Inconsistent with equals()
class Student {
String name;
int rollNo;
@Override
public boolean equals(Object obj) {
// Compares name and rollNo
}
@Override
public int hashCode() {
return name.hashCode(); // ✗ Only uses name
}
}
Hash Collision
Different objects with same hash code.
class Point {
int x, y;
Point(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public int hashCode() {
return x + y; // Simple hash
}
}
public class Main {
public static void main(String[] args) {
Point p1 = new Point(1, 2);
Point p2 = new Point(2, 1);
// Collision: same hash, different objects
System.out.println(p1.hashCode()); // 3
System.out.println(p2.hashCode()); // 3
System.out.println(p1.equals(p2)); // false
}
}
HashSet Internal Working
// When you do: set.add(object)
// Step 1: Calculate hash
int hash = object.hashCode();
// Step 2: Find bucket
int bucket = hash % bucketCount;
// Step 3: Check if exists in bucket
for (Object obj : buckets[bucket]) {
if (obj.equals(object)) {
return false; // Already exists
}
}
// Step 4: Add to bucket
buckets[bucket].add(object);
return true;
Performance Impact
Bad hashCode() - All Same:
@Override
public int hashCode() {
return 1; // ✗ All objects in one bucket - slow!
}
Good hashCode() - Well Distributed:
@Override
public int hashCode() {
return Objects.hash(field1, field2, field3);
}
Inheritance and hashCode()
class Person {
String name;
int age;
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
class Employee extends Person {
String empId;
@Override
public int hashCode() {
int result = super.hashCode(); // Include parent fields
result = 31 * result + empId.hashCode();
return result;
}
}
Testing hashCode()
class Student {
String name;
int rollNo;
Student(String name, int rollNo) {
this.name = name;
this.rollNo = rollNo;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Student s = (Student) obj;
return rollNo == s.rollNo && name.equals(s.name);
}
@Override
public int hashCode() {
return Objects.hash(name, rollNo);
}
}
public class Main {
public static void main(String[] args) {
Student s1 = new Student("John", 101);
Student s2 = new Student("John", 101);
Student s3 = new Student("Alice", 102);
// Test: equal objects → same hash
System.out.println("s1.equals(s2): " + s1.equals(s2)); // true
System.out.println("s1.hashCode() == s2.hashCode(): " +
(s1.hashCode() == s2.hashCode())); // true
// Test: different objects → possibly different hash
System.out.println("s1.equals(s3): " + s1.equals(s3)); // false
System.out.println("s1.hashCode() == s3.hashCode(): " +
(s1.hashCode() == s3.hashCode())); // likely false
// Test: consistency
int hash1 = s1.hashCode();
int hash2 = s1.hashCode();
System.out.println("Consistent: " + (hash1 == hash2)); // true
}
}
Template for hashCode()
@Override
public int hashCode() {
// Option 1: Using Objects.hash() (easy)
return Objects.hash(field1, field2, field3);
// Option 2: Manual calculation
int result = field1.hashCode();
result = 31 * result + field2.hashCode();
result = 31 * result + primitiveField;
return result;
// Option 3: Single field
return field.hashCode();
}
Quick Reference
import java.util.Objects;
class Example {
String field1;
int field2;
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Example e = (Example) obj;
return field2 == e.field2 && Objects.equals(field1, e.field1);
}
@Override
public int hashCode() {
return Objects.hash(field1, field2);
}
}
// Usage in collections
HashSet<Example> set = new HashSet<>();
HashMap<Example, String> map = new HashMap<>();
// Remember:
// - Always override with equals()
// - Use same fields as equals()
// - Keep consistent
// - Use Objects.hash() for simplicity
Exam Tips
Remember:
- hashCode() returns integer hash value
- Used in HashMap, HashSet
- Override with equals() (always together)
- Rule:
equals()true → same hash - Reverse not required: different objects can have same hash
- Use same fields as equals()
- Objects.hash() is easiest method
- 31 commonly used multiplier
- Consistent: same object → same hash
- Don’t use mutable fields
Common Questions:
- What is hashCode()?
- Why override hashCode()?
- hashCode() contract?
- Why override with equals()?
- What happens if not overridden?
- How to implement hashCode()?
- What is hash collision?
- Why use 31 in hashCode()?