HASH
📌 입력 데이터를 고정된 크기의 값으로 변환하는 함수 또는 그 과정을 의미합니다
- 다른 말로는 해시 값, 해시 코드, 체크섬 이라고 합니다.
- key와 value 쌍으로 데이터를 저장하며, 키를 해시 함수를 통해 고유한 인덱스에 대응시켜 빠르게 값을 조회합니다.
- 중복 허용을 안함, 순서 유지 안함, 빠른 검색, 삭제 가능
- 해시 함수를 통해 시간복잡도가 1(반드시 1은 아닙니다. 충돌할 경우 달라지기도 합니다.)인 한번에 정보의 위치를 찾을 수 있는 자료구조형태(해시 테이블)를 제작하는 과정
- 꼭 주소로 구현할 필요는 없다
- 왼쪽의 index/data table의 경우 이차원 배열로 map은 아니다.
- map으로 만들경우 메서드 차제적으로 for문으로 index값을 일일히 찾을 필요 없이 바로 index(key)를 찾을 수 있다.
- 그래서 시간복잡도가 1으로 속도 개선에 큰 장점을 가지게 된다.
- 위 그림은 엄밀히 말해, 에러난것, 키값이 중복되고 있다.
- 2번째는 map이 반드시 주소를 이용해 구현되는 것은 아니지만 주소를 이용할 경우, 삭제가 편하다
- 배열의 경우 삭제를 할 경우, 한번 복사를 하고 삭제를 하다보니 속도가 느리다. 다만 map의 경우 연결된 주소만 끊어버리면 삭제가 바로 진행되기에 삭제도 빠르다.
- 여기서 중요한게, 오른쪽의 Map은 HASH MAP이라 불러야 한다. MAP은 자료구조
해시의 사용 사례
- 해시 테이블(Hash Table):
- 키-값 쌍 데이터를 저장하고 검색할 때 사용. (예: Java의 HashMap, Python의 dict)
- 데이터베이스:
- 데이터베이스에서 인덱스를 생성하거나 검색 속도를 높이기 위해 사용.
- 캐싱(Caching):
- 자주 사용하는 데이터를 해시를 통해 빠르게 검색.
- 암호화 및 보안:
- 비밀번호 저장, 데이터 무결성 검증 등에 사용. (예: SHA-256, MD5)
- 파일 검색:
- 파일의 고유한 해시 값을 이용하여 중복 파일을 찾거나 무결성을 확인.
장점
- 빠른 검색 속도 (O(1))
- 해시 테이블을 사용하면 데이터를 저장하거나 검색하는 데 평균적으로 **O(1)**의 시간 복잡도를 가짐.
예: 키를 기반으로 바로 접근하므로 순차 탐색이 필요 없음.
- 해시 테이블을 사용하면 데이터를 저장하거나 검색하는 데 평균적으로 **O(1)**의 시간 복잡도를 가짐.
- 효율적인 데이터 저장 및 관리
- 다양한 크기의 데이터(문자열, 숫자 등)를 간단한 키-값 구조로 저장할 수 있음.
- 해시 함수를 통해 고정된 크기의 배열에 데이터를 저장해 메모리 사용을 최적화함.
- 충돌 해결 기법의 다양성
- 체이닝(Chaining), 오픈 어드레싱(Open Addressing) 등의 충돌 해결 기법으로 충돌 발생 시에도 효율적으로 처리 가능.
- 유연한 데이터 처리
- 문자열, 숫자, 객체 등 다양한 유형의 데이터를 처리할 수 있어 범용적임.
예: Java의 HashMap, Python의 dict처럼 키-값 쌍을 쉽게 저장하고 검색.
- 문자열, 숫자, 객체 등 다양한 유형의 데이터를 처리할 수 있어 범용적임.
- 확장성
- 데이터베이스, 캐싱 시스템, 파일 검색 등에서 널리 사용되며, 다양한 응용 가능.
- 보안 기능
- 해시 알고리즘(SHA-256, MD5 등)은 암호화, 데이터 무결성 검증 등에 사용됨.
단점
- 충돌(Collision) 문제
- 서로 다른 키가 같은 해시 값을 가질 경우 성능이 저하될 수 있음.
- 충돌 해결 기법을 적용해야 하며, 이로 인해 성능이 떨어질 수 있음.
- 예: 체이닝 사용 시, 연결 리스트를 순차적으로 탐색해야 하는 경우 발생.
- 메모리 낭비 가능성
- 해시 테이블은 초기 크기를 고정하거나 동적으로 조정하는데, 너무 큰 크기를 할당하면 메모리 낭비가 발생.
- 너무 작은 크기일 경우 충돌이 잦아져 성능 저하 가능.
- 정렬되지 않은 데이터
- 해시 테이블은 키-값을 저장하는 구조이므로 데이터가 정렬되지 않음.
- 정렬된 데이터가 필요하면 별도의 작업 필요.
- 해시 함수 설계의 중요성
- 해시 함수가 데이터를 균등하게 분배하지 못하면 충돌이 증가해 성능이 저하될 수 있음.
- 예: 키 값이 편향된 데이터(연속된 숫자 등)를 처리할 때.
- 해시 함수가 데이터를 균등하게 분배하지 못하면 충돌이 증가해 성능이 저하될 수 있음.
- 해시 함수의 연산 비용
- 복잡한 해시 함수는 연산 비용이 증가할 수 있어 작은 데이터에서는 오히려 비효율적.
- 재해시(Rehashing) 비용
- 테이블이 가득 차거나 특정 임계치를 초과할 경우 크기를 늘려야 하며, 이 과정에서 모든 데이터를 다시 해싱해야 함.
- 이는 큰 데이터셋에서 성능에 영향을 미칠 수 있음.
- 데이터 삭제 시 문제
- 오픈 어드레싱을 사용하는 경우, 데이터를 삭제하면 그 자리의 값이 비워지면서 연결된 데이터 검색에 영향을 줄 수 있음.
해시 함수 ( Hash Function )
📌 입력받은 데이터를 해시 값으로 출력시키는 알고리즘
- 알고리즘의 형태는 다양합니다. 목적에 맞게 다양하게 설계되고 유용하게 사용됩니다.
- 자료구조, 캐시, 검색, 에러 검출, 함도 등 유용하게 많이 사용됩니다.
// 해시 함수 예시
Integer hashFunction(String key) {
return (int)(key.charAt(0)) % 10;
}
- 위의 그림을 코드로 만든 것, 이 경우 위 그림처럼 return으로 key값을 반환해 준다.
해시 함수의 특징
- 일관성: 동일한 입력값에 대해 항상 동일한 해시 값을 반환.
- 고른 분배: 입력값이 다양해도 출력값이 균일하게 분포.
- 빠른 계산: 빠른 시간 안에 값을 계산.
- 충돌 최소화: 서로 다른 입력값이 동일한 해시 값을 가지는 확률을 낮춤.
해시 테이블 ( Hash Table )
📌 키와 값을 함께 저장해 둔 데이터 구조
- 아래와 같이 행, 열로 구성된 표에 저장되는 것과 유사합니다.
- 다만 테이블에 데이터를 저장할 때 순서는 무작위로 지정되어 저장됩니다.
- 그로인해 중간에 여유 공간이 발생할 수 있습니다.
- 해시 테이블은 map 형태의 자료구조입니다.
- 하나의 주소를 갖는 파일 영역을 Bucket, 한개의 레코드를 저장할 수 있는 공간을 Slot이라 말합니다.
해싱 ( Hashing )
📌 데이터를 해시 함수를 이용해 고유한 *해시 값(Hash Value)*으로 변환하는 과정
- 변환된 해시 값은 위 예시처럼 데이터의 저장 위치를 결정하거나, 데이터 검색 시 활용됩니다.
- 해싱을 잘못해서 key가 중복되면 충돌이 발생할 수 있습니다.
충돌 (Collision)
📌 해시 함수로 계산된 key값이 곂치는 경우, 동일한 값을 인덱스에 저장하려 할 때 발생합니다.
왜 충돌이 발생하는가?
- 해시 테이블 크기의 한계:
- 해시 값의 범위(테이블 크기)가 유한하기 때문에, 입력값(키)이 다양해도 모든 값을 고유한 해시 값으로 매핑할 수 없음.
- 예: 테이블 크기가 10이면, hash(21) = 1, hash(11) = 1처럼 서로 다른 키가 동일한 인덱스에 매핑될 수 있음.
- 해시 함수의 설계 문제:
- 해시 함수가 키를 균일하게 분산하지 못하거나 특정 키 값 패턴에 대해 편향된 결과를 생성하면 충돌 발생 가능성이 증가.
충돌 해결 방법
1. 체이닝 (Chaining)
- 방식: 충돌이 발생한 동일한 해시 값의 데이터를 연결 리스트(Linked List) 형태로 저장.
- 동작 과정:
- 충돌 시, 같은 인덱스에 새로운 데이터를 리스트의 형태로 추가.
- 데이터를 검색할 때 해당 인덱스의 리스트를 순회하며 원하는 데이터를 찾음.
- 장점:
- 테이블 크기를 초과하는 데이터도 저장 가능.
- 테이블의 크기를 크게 증가시키지 않아도 됨.
- 단점:
- 충돌이 많아지면 리스트가 길어져 검색 시간이 O(n)으로 증가.
2. 오픈 어드레싱 (Open Addressing)
- 방식: 충돌이 발생하면 다른 빈 슬롯(인덱스)을 찾아 데이터를 저장.
- 기법:
- 선형 탐사 (Linear Probing):
- 충돌이 발생하면 고정된 간격(보통 1)을 더해 다음 인덱스를 탐색.
- 예: hash(21) = 1에서 충돌 시, index = 2, index = 3 탐색.
단점: 충돌이 많아지면 클러스터링(연속된 충돌) 발생 가능. - 이차 탐사 (Quadratic Probing):
- 충돌 시 인덱스 이동 간격을 제곱 형태로 증가.
- 예: index = 1, index = 1 + 1^2, index = 1 + 2^2.
단점: 테이블의 크기가 소수(Prime)여야 효율적. - 이중 해싱 (Double Hashing):
- 충돌 시 다른 해시 함수를 사용해 새로운 위치를 계산.
- 예: hash1(21) = 1, 충돌 발생 시 hash2(21) = 3.
단점: 해시 함수 설계가 복잡.
- 선형 탐사 (Linear Probing):
충돌 해결 기법의 선택
- 데이터의 크기와 성격에 따라 충돌 해결 기법이 달라짐.
- 데이터가 많고 빈도가 높은 경우 → 체이닝 적합.
- 메모리가 제한적일 경우 → 오픈 어드레싱 적합.
충돌 해결 방법 비교
해시셋 ( Hashset )
📌 Set 인터페이스를 구현한 클래스 중 하나로, 데이터 중복, 순서를 유지하지 않는 집합입니다.
- HashMap, HashSet 등 해시 기반 컬렉션입니다.
- 컬렉션 = java에서 데이터를 효율적으로 저장하고 조작하기 위한 객체들의 그룹(container)을 말합니다.
HashSet의 작동 원리
HashSet은 내부적으로 HashMap을 사용해 데이터를 저장합니다.
데이터를 저장할 때, 키(key)와 값(value) 중에서 값(value)은 더미 객체로 설정되고, 키(key)만 저장됩니다.
- 저장: add(E e) 메서드를 호출하면, 입력 데이터의 해시 코드(hashCode)를 계산해 해시 테이블의 위치를 결정.
- 중복 확인: equals() 메서드를 사용해 중복 여부를 판단.
- 같은 해시 코드를 가진 데이터라도 equals() 메서드가 true를 반환하면 중복으로 간주.
import java.util.HashSet;
public class HashSetExample {
public static void main(String[] args) {
// HashSet 선언
HashSet<String> set = new HashSet<>();
// 데이터 추가
set.add("Apple");
set.add("Banana");
set.add("Cherry");
// 중복 추가 시 무시
set.add("Apple");
// 출력
System.out.println(set); // 출력: [Banana, Apple, Cherry] (순서가 랜덤)
// 특정 값 포함 여부 확인
System.out.println(set.contains("Banana")); // true
// 데이터 삭제
set.remove("Cherry");
// 크기 확인
System.out.println(set.size()); // 2
}
}
HashSet의 주요 메서드
- set의 주요 메서드를 계승하고 있습니다.
HashSet과 다른 Set 구현체 비교
Set 인터페이
🐳 중복을 허용하지 않는 집합(Collection)을 나타내는 인터페이스입니다.
Set의 주요 특징
- 중복 허용 안 함
- 동일한 요소를 여러 번 저장할 수 없습니다.
- 예: {1, 2, 2, 3} -> {1, 2, 3}
- 순서 유지 안 함
- 데이터의 저장 순서를 보장하지 않습니다.
- 일부 구현체(LinkedHashSet)는 예외적으로 삽입 순서를 유지.
- null 값
- null 값을 허용하지만, 한 번만 저장 가능.
- 기본 연산 지원
- 집합 연산을 쉽게 구현할 수 있습니다(교집합, 합집합, 차집합).
해시맵 ( Hashmap )
📌 Map 인터페이스의 구현체로, 키(Key)와 값(Value)의 쌍으로 데이터를 저장합니다.
- 각각의 키는 고유하며, 각 키에 대해 값을 매핑합니다. HashMap은 해시 테이블을 사용하여 데이터를 빠르게 검색하고 관리할 수 있도록 합니다.
- HashMap, HashSet 등 해시 기반 컬렉션입니다.
- 컬렉션 = java에서 데이터를 효율적으로 저장하고 조작하기 위한 객체들의 그룹(container)을 말합니다.
HashMap의 주요 특징
- 키-값 쌍(Key-Value Pair)
- HashMap은 데이터를 **키(Key)**와 **값(Value)**의 쌍으로 저장합니다.
- 키는 중복될 수 없고, 값은 중복될 수 있습니다.
- 예: map.put("Alice", 25)에서 "Alice"는 키, 25는 값입니다.
- 중복 키를 허용하지 않음
- 동일한 키로 여러 번 값을 넣으면, 기존의 값이 새로운 값으로 덮어씌워집니다.
- 예: map.put("Alice", 25) 이후 map.put("Alice", 30)을 호출하면 "Alice"의 값은 30으로 변경됩니다.
- 순서 보장하지 않음
- HashMap은 저장된 데이터를 순서대로 유지하지 않습니다.
순서가 중요한 경우, LinkedHashMap을 사용할 수 있습니다.
- HashMap은 저장된 데이터를 순서대로 유지하지 않습니다.
- 빠른 검색 속도
- HashMap은 해시 테이블을 사용하여 **O(1)**의 평균 시간 복잡도로 검색, 삽입, 삭제가 가능합니다.
- 해시 충돌을 처리하는 방법이 있기 때문에 최악의 경우에도 성능이 크게 저하되지는 않습니다.
- null 값 허용
- HashMap은 한 개의 null 키와 여러 개의 null 값을 허용합니다.
- 예: map.put(null, "some value") 또는 map.put("some key", null)이 가능합니다.
import java.util.HashMap;
public class HashMapExample {
public static void main(String[] args) {
// HashMap 생성
HashMap<String, Integer> map = new HashMap<>();
// 데이터 추가
map.put("Alice", 25); // "Alice" 키에 25 값 저장
map.put("Bob", 30); // "Bob" 키에 30 값 저장
map.put("Charlie", 35); // "Charlie" 키에 35 값 저장
// 값 출력
System.out.println("Alice's age: " + map.get("Alice")); // 출력: Alice's age: 25
// 존재 여부 확인
System.out.println("Contains 'Bob'? " + map.containsKey("Bob")); // 출력: Contains 'Bob'? true
// 모든 키와 값 출력
for (String key : map.keySet()) {
System.out.println(key + ": " + map.get(key));
}
// 출력:
// Alice: 25
// Bob: 30
// Charlie: 35
// 키 삭제
map.remove("Bob"); // "Bob" 삭제
System.out.println("Contains 'Bob' after removal? " + map.containsKey("Bob")); // 출력: false
}
}
HashMap의 성능
- 검색, 삽입, 삭제: 평균적으로 O(1)의 시간 복잡도를 가집니다.
- 해시 테이블을 사용하기 때문에, 키를 해시 함수로 변환하여 빠르게 위치를 찾습니다.
- 충돌 처리: 여러 항목이 동일한 해시 값을 갖는 경우 체이닝(Chaining) 또는 오픈 어드레싱(Open Addressing) 방식으로 충돌을 처리합니다.
- 최악의 경우: 해시 충돌이 많아지면, 검색/삽입/삭제가 O(n)으로 성능이 저하될 수 있습니다. 이를 방지하기 위해 적절한 해시 함수와 충돌 처리 전략이 중요합니다.
HashMap의 장점과 단점
장점
- 빠른 데이터 검색: 해시 테이블을 사용하여 평균적으로 O(1)의 시간 복잡도로 데이터를 빠르게 조회, 삽입, 삭제할 수 있습니다.
- 키를 통한 데이터 접근: 키를 사용하여 데이터를 빠르고 효율적으로 관리할 수 있습니다.
- null 허용: null 값을 키와 값에 사용할 수 있어 유연성 제공.
단점
- 순서 보장 없음: HashMap은 순서가 보장되지 않으므로, 데이터가 저장된 순서를 유지하려면 LinkedHashMap을 사용해야 합니다.
- 메모리 사용량: 해시 테이블은 추가 메모리를 사용하므로, 작은 데이터 세트에서는 오히려 비효율적일 수 있습니다.
- 충돌 처리 필요: 해시 충돌이 발생하면 성능이 저하될 수 있으므로, 충돌 처리 방법에 대한 고려가 필요합니다.
HashMap의 주요 메서드
HashCode( ) 메서드
📌Object 클래스에 정의된 메서드로, 객체를 식별하기 위한 정수 값(해시 코드)을 반환합니다. 이 값은 객체를 빠르게 검색하거나 비교할 때 사용됩니다.
hashCode()의 특징
- 정수 값 반환
- 객체의 해시 코드를 나타내는 정수를 반환.
- 예: 123456, -987654, 등.
- 같은 객체는 같은 해시 코드
- 동일한 객체(equals() 메서드로 비교 시 true)라면 동일한 hashCode를 반환해야 함.
- 하지만, 서로 다른 객체가 같은 해시 코드를 가질 수도 있음(해시 충돌).
- 기본 구현
- Object 클래스에서 기본적으로 정의되어 있으며, 객체의 메모리 주소를 기반으로 해시 코드를 생성.
- 재정의 가능
- 개발자가 특정 로직에 따라 hashCode()를 재정의 가능. 주로 equals() 메서드와 함께 재정의.
public class HashCodeExample {
public static void main(String[] args) {
Object obj1 = new Object();
Object obj2 = new Object();
System.out.println(obj1.hashCode()); // 출력: (예) 366712642
System.out.println(obj2.hashCode()); // 출력: (예) 1829164700
}
}
- obj1과 obj2는 서로 다른 객체이므로 해시 코드가 다름.
hashCode()와 equals()의 관계
- 규칙:
- equals()가 true인 두 객체는 항상 같은 hashCode() 값을 가져야 함.
- 그러나, 같은 hashCode() 값을 가진 객체가 **반드시 equals()가 true**는 아님.
- 의미:
- hashCode()는 빠른 검색을 위한 값이고,
- equals()는 객체의 논리적 동등성을 비교하는 메서드.
재정의된 hashCode()와 equals()
Java에서 hashCode()와 equals()는 함께 재정의해야 합니다.
HashSet이나 HashMap 같은 컬렉션은 hashCode()와 equals()의 일관성을 가정하여 동작합니다.
< 예제: 커스텀 클래스에서 hashCode()와 equals() 재정의 >
import java.util.Objects;
class Person {
String name;
int age;
// 생성자
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// hashCode() 재정의
@Override
public int hashCode() {
return Objects.hash(name, age);
}
// equals() 재정의
@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);
}
}
public class HashCodeEqualsExample {
public static void main(String[] args) {
Person p1 = new Person("Alice", 25);
Person p2 = new Person("Alice", 25);
// 해시 코드가 동일함
System.out.println(p1.hashCode() == p2.hashCode()); // true
// equals() 비교
System.out.println(p1.equals(p2)); // true
}
}
실행 결과:
- p1과 p2는 같은 name과 age를 가지므로 equals()와 hashCode() 모두 동일하게 동작.
hashCode()와 컬렉션
- HashSet, HashMap 등은 hashCode()를 사용해 데이터를 관리.
- 데이터를 추가할 때, 먼저 hashCode() 값으로 버킷(bucket)을 결정하고,
동일한 버킷에 여러 데이터가 들어올 경우 **equals()**로 중복 여부를 확인.
< 예제: HashSet에서 hashCode()와 equals() >
import java.util.HashSet;
class Student {
int id;
String name;
public Student(int id, String name) {
this.id = id;
this.name = name;
}
@Override
public int hashCode() {
return id; // ID를 기반으로 해시 코드 생성
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Student student = (Student) obj;
return id == student.id && name.equals(student.name);
}
}
public class HashSetExample {
public static void main(String[] args) {
HashSet<Student> set = new HashSet<>();
set.add(new Student(1, "Alice"));
set.add(new Student(1, "Alice")); // 중복 데이터
set.add(new Student(2, "Bob"));
System.out.println(set.size()); // 출력: 2
}
}
hashCode() 사용 시 주의점
- equals와 일관성 유지
- equals()가 true면 hashCode()도 같아야 함.
- 해시 충돌
- 서로 다른 객체가 같은 hashCode()를 가질 경우, 충돌 발생.
- 충돌이 많아지면 해시 기반 자료구조의 성능 저하.
- 재정의 필요성
- 사용자 정의 클래스에서는 반드시 hashCode()와 equals()를 함께 재정의해야 올바르게 동작.
equals메서드 정의시 항상 hashcode()를 함께 정의해야하는 이유
Java의 기본 규약
Java에서 equals()와 hashCode()의 관계를 다음과 같이 규정합니다:
- equals()가 true를 반환하는 두 객체는 반드시 같은 hashCode()를 가져야 한다.
- 동일한 객체를 나타내므로 동일한 해시코드가 필요.
- hashCode()가 같다고 해서 equals()가 반드시 true는 아니다.
- 다른 객체들이 해시 충돌을 일으킬 수 있음.
함께 정의하지 않으면 발생하는 문제
1. HashMap과 HashSet에서 데이터 검색 실패
- HashMap과 HashSet은 내부적으로 객체를 저장할 때 먼저 hashCode()로 버킷(bucket)을 찾고, 이후 equals()로 동등성을 확인합니다.
- 만약 equals()와 hashCode()가 일관되지 않다면, 검색, 삽입, 삭제 작업이 제대로 동작하지 않습니다.
import java.util.HashSet;
class Person {
String name;
public Person(String name) {
this.name = name;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Person person = (Person) obj;
return name.equals(person.name);
}
// hashCode()를 정의하지 않음
}
public class HashCodeEqualsTest {
public static void main(String[] args) {
HashSet<Person> set = new HashSet<>();
set.add(new Person("Alice"));
// 동일한 이름의 객체를 검색하려고 함
System.out.println(set.contains(new Person("Alice"))); // false
}
}
원인
- equals()는 동일한 객체라고 판단하지만, hashCode()를 재정의하지 않았으므로 다른 해시 버킷에 저장됩니다.
- 결과적으로 HashSet은 데이터를 찾지 못합니다.
< 수정 >
import java.util.Objects;
class Person {
String name;
public Person(String name) {
this.name = name;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Person person = (Person) obj;
return name.equals(person.name);
}
@Override
public int hashCode() {
return Objects.hash(name); // name 기반으로 해시코드 생성
}
}
public class HashCodeEqualsTest {
public static void main(String[] args) {
HashSet<Person> set = new HashSet<>();
set.add(new Person("Alice"));
// 동일한 이름의 객체를 검색
System.out.println(set.contains(new Person("Alice"))); // true
}
}
결과
- equals()와 hashCode()를 함께 재정의하여, 동일한 이름의 객체를 올바르게 검색합니다.
왜 hashCode()를 함께 정의해야 하는가?
- 효율성:
- hashCode()는 검색을 빠르게 하기 위해 사용됩니다.
(equals()는 최종 확인 단계로만 호출되므로 성능 부담이 적음).
- hashCode()는 검색을 빠르게 하기 위해 사용됩니다.
- 충돌 방지:
- hashCode()가 올바르게 정의되지 않으면, 모든 데이터가 같은 해시 버킷에 저장되어 성능이 크게 저하됩니다.
예: O(1) → O(n)
- hashCode()가 올바르게 정의되지 않으면, 모든 데이터가 같은 해시 버킷에 저장되어 성능이 크게 저하됩니다.
- 컬렉션 동작 보장:
- HashMap, HashSet 등 해시 기반 컬렉션이 의도한 대로 작동하려면 반드시 두 메서드가 일관성 있어야 합니다.
정리
- equals()는 객체의 논리적 동등성을 비교.
- hashCode()는 빠른 검색과 데이터 저장을 위해 사용.
- 두 메서드는 일관성을 유지해야 하며, 함께 재정의하지 않으면 해시 기반 자료구조가 잘못 동작하거나 성능이 저하될 수 있습니다.
따라서 항상 equals()와 hashCode()를 함께 재정의하세요.
'Back-End (Web) > JAVA' 카테고리의 다른 글
[JAVA] JAVA 웹 기술의 역사 (0) | 2024.12.12 |
---|---|
[JAVA] 열거형 ( Enum ) (0) | 2024.11.22 |
[JAVA] 자바의 정렬 (0) | 2024.11.21 |
[JAVA] 응용 정리 (1) | 2024.11.15 |
[JAVA] NULL (0) | 2024.11.13 |