From 43eaaa44373e7ccb774cc503cf6089d682d58a57 Mon Sep 17 00:00:00 2001
From: yerim <97941141+yerim123456@users.noreply.github.com>
Date: Sat, 11 Jan 2025 10:09:16 +0900
Subject: [PATCH 1/9] =?UTF-8?q?refactor:=20=EC=98=A4=ED=83=80=20=EC=88=98?=
=?UTF-8?q?=EC=A0=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
...4\234 \354\247\204\355\226\211\355\225\230\353\235\274.md" | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git "a/3\354\236\245_\353\252\250\353\223\240_\352\260\235\354\262\264\354\235\230_\352\263\265\355\206\265_\353\251\224\354\204\234\353\223\234/\354\225\204\354\235\264\355\205\234 13/clone \354\236\254\354\240\225\354\235\230\353\212\224 \354\243\274\354\235\230\355\225\264\354\204\234 \354\247\204\355\226\211\355\225\230\353\235\274.md" "b/3\354\236\245_\353\252\250\353\223\240_\352\260\235\354\262\264\354\235\230_\352\263\265\355\206\265_\353\251\224\354\204\234\353\223\234/\354\225\204\354\235\264\355\205\234 13/clone \354\236\254\354\240\225\354\235\230\353\212\224 \354\243\274\354\235\230\355\225\264\354\204\234 \354\247\204\355\226\211\355\225\230\353\235\274.md"
index 63aad46..dd03a5f 100644
--- "a/3\354\236\245_\353\252\250\353\223\240_\352\260\235\354\262\264\354\235\230_\352\263\265\355\206\265_\353\251\224\354\204\234\353\223\234/\354\225\204\354\235\264\355\205\234 13/clone \354\236\254\354\240\225\354\235\230\353\212\224 \354\243\274\354\235\230\355\225\264\354\204\234 \354\247\204\355\226\211\355\225\230\353\235\274.md"
+++ "b/3\354\236\245_\353\252\250\353\223\240_\352\260\235\354\262\264\354\235\230_\352\263\265\355\206\265_\353\251\224\354\204\234\353\223\234/\354\225\204\354\235\264\355\205\234 13/clone \354\236\254\354\240\225\354\235\230\353\212\224 \354\243\274\354\235\230\355\225\264\354\204\234 \354\247\204\355\226\211\355\225\230\353\235\274.md"
@@ -109,8 +109,8 @@ Entry deepCopy(){
> 좋은 방식은 아니다. 생성자에서는 재정의될 수 있는 메서드를 호출하지 않아야 하는데 clone 메서드도 마찬가지이기 때문이다.
### 주의점
-- 상속용 클래스의 경우 loneable을 구현해서는 안됨
-- 스레드 안전 클래스 작성 시 Clneable을 구현하는 모든 클래스는 clone을 재정의해야 함(접근 제한자는 pubic, 반환 타입은 클래스 자신)
+- 상속용 클래스의 경우 Cloneable을 구현해서는 안됨
+- 스레드 안전 클래스 작성 시 Cloneable을 구현하는 모든 클래스는 clone을 재정의해야 함(접근 제한자는 public, 반환 타입은 클래스 자신)
### 가능한 다른 선택지! 변환 생성자/ 변환 팩터리
From 97c0c993994def9f01f3745058e6763662318725 Mon Sep 17 00:00:00 2001
From: yerim <97941141+yerim123456@users.noreply.github.com>
Date: Thu, 16 Jan 2025 22:54:04 +0900
Subject: [PATCH 2/9] feat: Add item 11.md
---
...04\355\226\211\355\225\230\353\235\274.md" | 86 +++++++++++++++++++
1 file changed, 86 insertions(+)
create mode 100644 "3\354\236\245_\353\252\250\353\223\240_\352\260\235\354\262\264\354\235\230_\352\263\265\355\206\265_\353\251\224\354\204\234\353\223\234/\354\225\204\354\235\264\355\205\234 11/clone_\354\236\254\354\240\225\354\235\230\353\212\224_\354\243\274\354\235\230\355\225\264\354\204\234_\354\247\204\355\226\211\355\225\230\353\235\274.md"
diff --git "a/3\354\236\245_\353\252\250\353\223\240_\352\260\235\354\262\264\354\235\230_\352\263\265\355\206\265_\353\251\224\354\204\234\353\223\234/\354\225\204\354\235\264\355\205\234 11/clone_\354\236\254\354\240\225\354\235\230\353\212\224_\354\243\274\354\235\230\355\225\264\354\204\234_\354\247\204\355\226\211\355\225\230\353\235\274.md" "b/3\354\236\245_\353\252\250\353\223\240_\352\260\235\354\262\264\354\235\230_\352\263\265\355\206\265_\353\251\224\354\204\234\353\223\234/\354\225\204\354\235\264\355\205\234 11/clone_\354\236\254\354\240\225\354\235\230\353\212\224_\354\243\274\354\235\230\355\225\264\354\204\234_\354\247\204\355\226\211\355\225\230\353\235\274.md"
new file mode 100644
index 0000000..1b07c96
--- /dev/null
+++ "b/3\354\236\245_\353\252\250\353\223\240_\352\260\235\354\262\264\354\235\230_\352\263\265\355\206\265_\353\251\224\354\204\234\353\223\234/\354\225\204\354\235\264\355\205\234 11/clone_\354\236\254\354\240\225\354\235\230\353\212\224_\354\243\274\354\235\230\355\225\264\354\204\234_\354\247\204\355\226\211\355\225\230\353\235\274.md"
@@ -0,0 +1,86 @@
+## item 11
+
+### equals를 재정의하려거든 hashCode도 재정의하라
+
+---
+
+### 🙋♀️ 왜 함께 재정의해줘야 하나요?
+
+`hashCode` 일반 규약을 어기게 되어 해당 클래스의 인스턴스를 `HashMap`이나 `HashSet` 같은 컬렉션의 원소로 사용할 때 문제를 일으킬 것이기 때문입니다.
+
+---
+
+### 🙋 hashCode 의 일반 규약은 무엇인가요?
+다음은 규약 중 일부입니다.
+#### 1. equals 비교에 사용되는 핵심 필드가 달라지지 않았다면, hashCode 메서드는 몇 번을 호출해도 일관되게 항상 같은 값을 반환해야 합니다.
+#### 2. equals 비교를 통해 같다고 판명된 객체라면, 각 객체의 hashCode는 똑같은 값을 반환해야 합니다.
+#### 3. equals 비교를 통해 다르다고 판단된 값이라도, 서로 다른 값을 반환할 필요는 없습니다. 다만!! 다른 객체라면 다른 값을 반환하는 게 해시테이블의 성능이 좋아집니다.
+
+---
+
+### 🙌 hashCode 재정의를 잘못한다면 2번 조항에서 문제가 생깁니다.
+간단히 말하자면, `equals`에서는 같은 객체라고 판단했으나 `hashCode`에 대한 재정의가 잘못되어서 `HashMap`이나 `HashSet`에서 같은 원소로 판별되지 않는 문제가 생긴다는 것입니다.
+
+`equals`는 물리적으로 다른 두 객체를 논리적으로 같은 객체라고 판단할 수 있지만 `hashCode`를 재정의하지 않는다면 `hashCode`는 이를 모를 것이기 때문입니다.
+
+---
+
+### 🙋♀️ 그럼 hashCode는 어떻게 구현하는 게 올바른 방법인가요?
+
+#### 최악의 방법
+```java
+@Override
+public int hashCode(){
+ return 42;
+}
+```
+`동치인` 모든 객체에서 똑같은 해시코드를 반환하기에 적법합니다.
+문제는 `동치가 아닌` 객체에서도 똑같은 해시코드를 반환하기 때문에 생깁니다.
+결과적으로 해시테이블의 버킷 하나에 모두 담겨 연결 리스트처럼 동작하고, 평균 수행 시간이 0(1) > O(n)으로 느려져서 객체가 많아지면 도저히 쓸 수 없게 됩니다.
+
+---
+
+#### 좋은 방법
+```java
+@Override
+public int hashCode(){
+ int result = Short.hashCode(areaCode);
+ result = 31 * result + Short.hashCode(prefix);
+ result = 31 * result + Short.hashCode(lineNum);
+ return result;
+}
+```
+좋은 해시 함수라면 서로 다른 인스턴스에 다른 해시코드를 반환합니다.(3번 조항)
+##### 1) int 변수 result를 선언한 후 `첫번째 핵심 필드`를 단계 `2.a 방식으로 계산`한 해시코드로 초기화합니다.
+##### 2) 해당 객체의 나머지 핵심 필드에 대한 작업을 수행합니다.
+| 필드 형식 및 조건 | 처리 방식 |
+|--------------------------|------------------------------------------------------------------------------|
+| 기본 타입 | `Type.hashCode(f)` |
+| 참조 타입 + equals 재귀 호출 처리 | 해당 필드의 `hashCode` 재귀 호출 / 필드의 표준형 제작 |
+| 배열 | 배열의 참조값이 아닌 각 핵심 원소에 대한 값을 처리하며 갱신(누적) / 모든 원소가 핵심 원소라면, Arrays.hashCode를 사용 |
+
+#### 3) 계산한 해시코드로 result 갱신
+#### 4) result 반환
+#### 5) 동치인 인스턴스에 대해 똑같은 해시 코드를 반환하는지 테스트
+#### 6) 단위 테스트 작성
+
+---
+
+✔ 추가 주의점
+#### 1) null, 핵심 원소 X 배열 > 상수, 특히 0으로 처리하기
+#### 2) 파생 필드는 계산에서 제외하기
+#### 3) equals 비교에 사용되지 않은 필드 반드시 제외하기
+#### 4) result와 곱하는 수는 짝수이거나 오버플로가 발생하면 안됨(31 추천)
+#### 5) 성능 개선 때문에 핵심 필드 생략을 해선 안됨, 되레 속도가 느려질 가능성 있음
+
+---
+
+✔ 추가 개선 사항
+#### 1) 코드를 줄이기 위해 hash 메서드를 사용할 수 있으나 성능에 민감하지 않은 상황에서만 사용하기
+#### 2) 클래스가 불변, 해시코드를 계산하는 비용이 크다면 캐싱을 고려(해당 타입의 객체가 해시의 키로 사용)
+#### 3) 해시의 키로 사용되지 않는다면,지연 초기화 전략 사용
+#### 4) hashCode가 반환하는 값의 생성 규칙을 API 사용자에게 자세히 공표하지 말기
+
+이에 따라서 핵심 필드 3개만을 사용하여 간단히 계산이 가능해졌습니다.
+
+---
From e29e74fc21d7d9680ac3f03e349cf7a1348c5bbc Mon Sep 17 00:00:00 2001
From: yerim <97941141+yerim123456@users.noreply.github.com>
Date: Thu, 16 Jan 2025 22:55:51 +0900
Subject: [PATCH 3/9] feat: Add item 23.md
---
...34\354\232\251\355\225\230\353\235\274.md" | 233 ++++++++++++++++++
1 file changed, 233 insertions(+)
create mode 100644 "4\354\236\245_\355\201\264\353\236\230\354\212\244\354\231\200_\354\235\270\355\204\260\355\216\230\354\235\264\354\212\244/\354\225\204\354\235\264\355\205\234 23/\355\203\234\352\267\270_\353\213\254\353\246\260_\355\201\264\353\236\230\354\212\244\353\263\264\353\213\244\353\212\224_\355\201\264\353\236\230\354\212\244_\352\263\204\354\270\265\352\265\254\354\241\260\353\245\274_\355\231\234\354\232\251\355\225\230\353\235\274.md"
diff --git "a/4\354\236\245_\355\201\264\353\236\230\354\212\244\354\231\200_\354\235\270\355\204\260\355\216\230\354\235\264\354\212\244/\354\225\204\354\235\264\355\205\234 23/\355\203\234\352\267\270_\353\213\254\353\246\260_\355\201\264\353\236\230\354\212\244\353\263\264\353\213\244\353\212\224_\355\201\264\353\236\230\354\212\244_\352\263\204\354\270\265\352\265\254\354\241\260\353\245\274_\355\231\234\354\232\251\355\225\230\353\235\274.md" "b/4\354\236\245_\355\201\264\353\236\230\354\212\244\354\231\200_\354\235\270\355\204\260\355\216\230\354\235\264\354\212\244/\354\225\204\354\235\264\355\205\234 23/\355\203\234\352\267\270_\353\213\254\353\246\260_\355\201\264\353\236\230\354\212\244\353\263\264\353\213\244\353\212\224_\355\201\264\353\236\230\354\212\244_\352\263\204\354\270\265\352\265\254\354\241\260\353\245\274_\355\231\234\354\232\251\355\225\230\353\235\274.md"
new file mode 100644
index 0000000..fc41798
--- /dev/null
+++ "b/4\354\236\245_\355\201\264\353\236\230\354\212\244\354\231\200_\354\235\270\355\204\260\355\216\230\354\235\264\354\212\244/\354\225\204\354\235\264\355\205\234 23/\355\203\234\352\267\270_\353\213\254\353\246\260_\355\201\264\353\236\230\354\212\244\353\263\264\353\213\244\353\212\224_\355\201\264\353\236\230\354\212\244_\352\263\204\354\270\265\352\265\254\354\241\260\353\245\274_\355\231\234\354\232\251\355\225\230\353\235\274.md"
@@ -0,0 +1,233 @@
+## item 23
+
+### 태그 달린 클래스보다는 클래스 계층구조를 활용하라
+
+---
+
+### 🙋♀️ `태그 달린 클래스`는 무엇인가요?
+
+```java
+import java.awt.Shape;
+
+class Figure {
+ enum Shape {RECTANGLE, CIRCLE}
+
+ ;
+
+ // 태그 필드 - 현재 모양을 나타낸다.
+ final Shape shape;
+
+ // 다음 필드들은 모양이 사각형(RECTANGLE)일 때만 쓰인다.
+ double length;
+ double width;
+
+ // 다음 필드는 모양이 원(CIRCLE)일 때만 쓰인다.
+ double radius;
+
+ // 다음 필드는 공통적으로 사용된다.
+ final double x;
+ final double y;
+
+ // 원용 생성자
+ Figure(double x, double y, double radius) {
+ shape = Shape.CIRCLE;
+ this.x = x;
+ this.y = y;
+ this.radius = radius;
+ }
+
+ // 사각형용 생성자
+ Figure(double x, double y,double length, double width) {
+ shape = Shape.RECTANGLE;
+ this.x = x;
+ this.y = y;
+ this.length = length;
+ this.width = width;
+ }
+
+ // Shape의 종류와 관계 없이 현재 위치 반환하는 메서드
+ String getFormattedPosition() {
+ return String.format("현재 위치는 %.0f, %.0f 입니다.", x, y);
+ }
+
+ double area() {
+ switch (shape) {
+ case RECTANGLE:
+ return length * width;
+ case CIRCLE:
+ return Math.PI * (radius * radius);
+ default:
+ throw new AssertionError(shape);
+ }
+ }
+}
+```
+
+
+태그가 달린 클래스는 `두 가지 이상의 의미를 표현`할 수 있으며 현재 `표현하는 의미를 태그 값`으로 알려주는 클래스입니다.
+
+---
+
+### 🙋♀️ 위의 예제의 단점은 무엇인가요?
+
+장황하고, 오류를 내기 쉽고, 비효율적입니다.
+
+#### 1) `두 가지 이상의 의미를 하나의 클래스에서 표현`하기 위해 `쓸데없는 코드`가 많습니다. > 가독성과 메모리 차지 ↑
+
+#### 2) `필드를 final 로 선언하려면` 해당하는 의미에 `쓰이지 않는 필드들까지 초기화`가 필요합니다. > 컴파일러 에러 인지 X / 런타임 에러 발견 가능성 ↑
+
+#### 3) `새로운 의미 추가`를 위해 `root 클래스에 불필요한 코드를 추가`해야 합니다. > 컴파일러 에러 인지 X / 런타임 에러 발견 가능성 ↑
+
+#### 4) `Figure` 라는 인스턴스의 타입만으로는 `현재 나타내는 의미(RECTANCLE, CIRCLE, ..)`를 알 길이 없음 > 가독성과 코드 이해도 ↓
+
+---
+
+### 🙌 태그가 달린 클래스를 대체하는 것, 서브타이핑
+
+이런 상황에서 `타입 하나`로 `다양한 의미의 객체를 표현`하는 훨씬 나은 수단을 제공하는데,
+이가 `클래스 계층구조를 활용`하는 `서브 타이핑`입니다.
+`서브 타이핑` 이란, 하위 타입이 상위 타입을 대체할 수 있다는 개념으로,
+`리스코프 치환 원칙`에 따라 동작합니다.
+
+계층 구조라고 하는 것은 코드를 보면 쉽게 이해할 수 있습니다.
+현재 구현된 것과 상속된 것을 정리해보면 `Figure > Rectangle > Square` 로 계층 구조를 이룹니다.
+
+```java
+import java.awt.Shape;
+
+abstract class Figure {
+ final double x; // x 좌표
+ final double y; // y 좌표
+
+ // 생성자: x와 y 좌표 초기화
+ Figure(double x, double y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ // 추상 메서드: 면적 계산
+ abstract double area();
+
+ // 현재 위치 반환하는 일반 메서드
+ String getFormattedPosition() {
+ return String.format("현재 위치는 %.0f, %.0f 입니다.", x, y);
+ }
+}
+```
+
+```java
+class Rectangle extends Figure {
+ final double length;
+ final double width;
+
+ Rectangle(double x, double y, double length, double width) {
+ super(x, y); // 부모 클래스 생성자 호출
+ this.length = length;
+ this.width = width;
+ }
+
+ @Override
+ double area() {
+ return length * width;
+ }
+}
+```
+
+```java
+class Square extends Rectangle {
+ Square(double x, double y, double side) {
+ super(x, y, side, side); // 부모 클래스 생성자 호출
+ }
+}
+```
+
+위의 클래스를 아래처럼 사용하면,
+`Figure` 클래스 하나로 `Rectangle`, `Circle`, `Square` 등 다양한 의미의 객체를 표현할 수 있습니다.
+
+```java
+public static void main(String[] args) {
+ Figure rectangle = new Rectangle(5, 10);
+ Figure square = new Square(5);
+
+ System.out.println(rectangle.area()); // 50.0
+ System.out.println(square.area()); // 25.0
+}
+```
+
+---
+
+### ✅ `태그 달린 클래스` > `클래스 계층구조`로 리팩토링하는 방법!
+
+위의 예제 코드는 태그 달린 클래스였던 `Figure` 클래스를 리팩토링한 것입니다.
+그럼 어떻게 할 수 잇는지 알아보겠습니다.
+
+### 추상 클래스 정의
+#### 1) 계층구조의 root가 될 추상 클래스를 정의 [Figure abstract class]
+#### 2) 태그 값에 따라 동작이 달라지는 메서드를 추상 메서드로 정의 [Figure > area abstract method]
+#### 3) 태그 값에 따라 동작이 달라지지 않는 메서드를 일반 메서드로 추가 [Figure > getFormattedPosition method]
+#### 4) 하위 클래스에서 공통으로 사용하는 데이터 필드 루트 클래스로 추가 [Figure > x, y final field]
+
+📑 완성된 코드
+
+```java
+import java.awt.Shape;
+
+abstract class Figure {
+ final double x; // x 좌표
+ final double y; // y 좌표
+
+ // 생성자: x와 y 좌표 초기화
+ Figure(double x, double y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ // 추상 메서드: 면적 계산
+ abstract double area();
+
+ // 현재 위치 반환하는 일반 메서드
+ String getFormattedPosition() {
+ return String.format("현재 위치는 %.0f, %.0f 입니다.", x, y);
+ }
+}
+```
+
+
+
+
+
+### 구체 클래스 정의
+#### 1) 의미별로 루트 클래스를 확장한 구체클래스 정의 [Rectangle, Circle, ...]
+#### 2) 각자 의미에 맞는 데이터 필드 추가 [Rectangle > length, width, Circle > radius]
+#### 3) 추상 메서드 구현 [area abstract method overriding]
+
+📑 완성된 코드
+
+```java
+class Rectangle extends Figure {
+ final double length;
+ final double width;
+
+ Rectangle(double x, double y, double length, double width) {
+ super(x, y); // 부모 클래스 생성자 호출
+ this.length = length;
+ this.width = width;
+ }
+
+ @Override
+ double area() {
+ return length * width;
+ }
+}
+```
+
+
+
+---
+
+### 🙌 달라진 점
+#### 1) `관련 없던 데이터 필드 모두 제거`됨 (살아남은 필드는 모두 final)
+#### 2) 런타임 오류가 발생하기 전에 추상 메서드 구현을 `컴파일러가 확인`해줌 (switch 문에 case 미포함으로 인한 에러 발생 X)
+#### 3) 루트 클래스의 코드에 접근하지 않고도 `독립적으로 계층구조 확장이 가능`
+#### 4) `타입이 의미 별로 존재`하기에 변수 의미 명시 및 제한, 변수에 따른 의미 별 매겨변수 설정 가능
+#### 5) `타입 사이 자연스런 계층 관게 반영 가능` > 유연성 + 컴파일타임 타입 검사 능력 ↑ (ex Square 클래스)
From fb874878ab274bd928464bf8b5b01e9625f9b84d Mon Sep 17 00:00:00 2001
From: yerim <97941141+yerim123456@users.noreply.github.com>
Date: Thu, 16 Jan 2025 22:59:50 +0900
Subject: [PATCH 4/9] refactor: Fix file name
---
...54\236\254\354\240\225\354\235\230\355\225\230\353\235\274.md" | 0
1 file changed, 0 insertions(+), 0 deletions(-)
rename "3\354\236\245_\353\252\250\353\223\240_\352\260\235\354\262\264\354\235\230_\352\263\265\355\206\265_\353\251\224\354\204\234\353\223\234/\354\225\204\354\235\264\355\205\234 11/clone_\354\236\254\354\240\225\354\235\230\353\212\224_\354\243\274\354\235\230\355\225\264\354\204\234_\354\247\204\355\226\211\355\225\230\353\235\274.md" => "3\354\236\245_\353\252\250\353\223\240_\352\260\235\354\262\264\354\235\230_\352\263\265\355\206\265_\353\251\224\354\204\234\353\223\234/\354\225\204\354\235\264\355\205\234 11/equals\353\245\274_\354\236\254\354\240\225\354\235\230\355\225\230\353\240\244\352\261\260\353\223\240_hashCode\353\217\204_\354\236\254\354\240\225\354\235\230\355\225\230\353\235\274.md" (100%)
diff --git "a/3\354\236\245_\353\252\250\353\223\240_\352\260\235\354\262\264\354\235\230_\352\263\265\355\206\265_\353\251\224\354\204\234\353\223\234/\354\225\204\354\235\264\355\205\234 11/clone_\354\236\254\354\240\225\354\235\230\353\212\224_\354\243\274\354\235\230\355\225\264\354\204\234_\354\247\204\355\226\211\355\225\230\353\235\274.md" "b/3\354\236\245_\353\252\250\353\223\240_\352\260\235\354\262\264\354\235\230_\352\263\265\355\206\265_\353\251\224\354\204\234\353\223\234/\354\225\204\354\235\264\355\205\234 11/equals\353\245\274_\354\236\254\354\240\225\354\235\230\355\225\230\353\240\244\352\261\260\353\223\240_hashCode\353\217\204_\354\236\254\354\240\225\354\235\230\355\225\230\353\235\274.md"
similarity index 100%
rename from "3\354\236\245_\353\252\250\353\223\240_\352\260\235\354\262\264\354\235\230_\352\263\265\355\206\265_\353\251\224\354\204\234\353\223\234/\354\225\204\354\235\264\355\205\234 11/clone_\354\236\254\354\240\225\354\235\230\353\212\224_\354\243\274\354\235\230\355\225\264\354\204\234_\354\247\204\355\226\211\355\225\230\353\235\274.md"
rename to "3\354\236\245_\353\252\250\353\223\240_\352\260\235\354\262\264\354\235\230_\352\263\265\355\206\265_\353\251\224\354\204\234\353\223\234/\354\225\204\354\235\264\355\205\234 11/equals\353\245\274_\354\236\254\354\240\225\354\235\230\355\225\230\353\240\244\352\261\260\353\223\240_hashCode\353\217\204_\354\236\254\354\240\225\354\235\230\355\225\230\353\235\274.md"
From cab87165ee25d3ccab1c8abe76a74b8984426d80 Mon Sep 17 00:00:00 2001
From: yerim <97941141+yerim123456@users.noreply.github.com>
Date: Thu, 16 Jan 2025 23:59:55 +0900
Subject: [PATCH 5/9] feat: Add item 17.md
---
...14\355\231\224\355\225\264\353\235\274.md" | 139 ++++++++++++++++++
1 file changed, 139 insertions(+)
create mode 100644 "3\354\236\245_\353\252\250\353\223\240_\352\260\235\354\262\264\354\235\230_\352\263\265\355\206\265_\353\251\224\354\204\234\353\223\234/\354\225\204\354\235\264\355\205\234 17/\353\263\200\352\262\275_\352\260\200\353\212\245\354\204\261\354\235\204_\354\265\234\354\206\214\355\231\224\355\225\264\353\235\274.md"
diff --git "a/3\354\236\245_\353\252\250\353\223\240_\352\260\235\354\262\264\354\235\230_\352\263\265\355\206\265_\353\251\224\354\204\234\353\223\234/\354\225\204\354\235\264\355\205\234 17/\353\263\200\352\262\275_\352\260\200\353\212\245\354\204\261\354\235\204_\354\265\234\354\206\214\355\231\224\355\225\264\353\235\274.md" "b/3\354\236\245_\353\252\250\353\223\240_\352\260\235\354\262\264\354\235\230_\352\263\265\355\206\265_\353\251\224\354\204\234\353\223\234/\354\225\204\354\235\264\355\205\234 17/\353\263\200\352\262\275_\352\260\200\353\212\245\354\204\261\354\235\204_\354\265\234\354\206\214\355\231\224\355\225\264\353\235\274.md"
new file mode 100644
index 0000000..d486b10
--- /dev/null
+++ "b/3\354\236\245_\353\252\250\353\223\240_\352\260\235\354\262\264\354\235\230_\352\263\265\355\206\265_\353\251\224\354\204\234\353\223\234/\354\225\204\354\235\264\355\205\234 17/\353\263\200\352\262\275_\352\260\200\353\212\245\354\204\261\354\235\204_\354\265\234\354\206\214\355\231\224\355\225\264\353\235\274.md"
@@ -0,0 +1,139 @@
+## item 17
+
+### 변경 가능성을 최소화하라
+
+---
+
+### 🙋♀️ 왜 변경 가능성을 최소화하는 게 좋은가요?
+변경 가능성이 최소화된 클래스를 `불변 클래스`라고 합니다. 이는 인스턴스 내부 값을 수정할 수 없는 클래스로, 객체가 파괴되는 순간까지 절대 달라지지 않습니다.
+
+이런 클래스를 지향해야 하는 이유는 가변 클래스보다 설계하고 구현하고 사용하기 쉬우며,
+오류가 생길 여지도 적고, 안전하기 때문입니다.
+
+#### 1) 상대적으로 설계,구현,사용이 쉬움
+- 불변:
+ - 프로그래머의 노력 없이도 영원히 불변으로 남음
+ - 값이 바뀌지 않는 상태이기에 구조가 아무리 복잡해도 불변식을 유지하기 쉬움 (실패 원자성)
+ - 불변 객체인 경우 불변 객체끼리는 내부 데이터 공유도 가능함
+- 가변: 메서드에 의해 임의의 복잡한 상태에 놓일 수 있음
+ - 따라서 가변 객체 사용시에는 클래스의 보안을 지키기 위해 진짜 해당 객체인지 확인해야 함
+
+#### 2) 스레드 안전
+- 근본적으로 스레드 안전하여 따로 동기화할 필요 X
+- 따라서 안심하고 공유가 가능하고, 그렇기에 최대한 재활용하는 게 좋음
+- 상수로 선언하거나, 정적 팩터리를 통해 생성하여 중복 생성을 피하고, 메모리 사용량/가비지 컬렉션 비용을 줄일 수 있음
+- 결국 추후에 나올 `방어적 복사`도 필요 없게 만듦(1번 장점에 해당)
+
+---
+
+### 🙋♀️ 불변 클래스는 어떻게 만들 수 있나요?
+
+아래의 다섯 가지 규칙을 잘 따르면 됩니다.
+#### 1) 객체의 상태를 변경하는 메서드를 제공하지 않는다.
+#### 2) 클래스를 확장할 수 없도록 한다. 하위 클래스에서 객체의 상태를 변하게 하는 것을 막아준다. (final 클래스로 정의 / 생성자를 private, protected로 정의)
+#### 3) 모든 필드를 `final`로 선언한다. 불변으로 명시적으로 선언하여 설계자의 의도를 명확히 들어낸다.
+#### 4) 모든 필드를 `private`로 선언한다. 필드가 참조하는 가변 객체를 클라이언트에서 직접 접근하여 수정하는 일을 막아준다. `public`으로 정의한 경우, 내부 표현을 쉽게 바꾸지 못하기에 `private`을 추천한다.
+#### 5) 자신 외에는 내부의 가변 컴포넌트에 접근할 수 없도록 한다. 클래스에 가변 객체를 참조하고 있는 필드가 있다면, 클라이언트에서 그 객체를 변경할 수 있다.
+✅ 5번의 해결책 방어적 복사
+
+1) `List` 가변 객체를 참조하는 필드가 있는 클래스에서, 해당 객체를 그대로 반환하고 있습니다.
+```java
+public final class ImmutableClass {
+ private final List items;
+
+ public ImmutableClass(List items) {
+ this.items = items; // 가변 리스트를 직접 참조
+ }
+
+ // 가변 객체를 직접 반환
+ public List getItems() {
+ return items; // 외부에서 이 리스트를 수정할 수 있음
+ }
+}
+```
+
+2) 이 과정에서 문제가 발생합니다. 외부에서도 해당 객체의 내부 필드에 직접 접근하여 수정이 가능해지기 때문에 불변성을 보장받지 못하기 때문입니다.
+```java
+public static void main(String[] args) {
+ List list = new ArrayList<>();
+ list.add("item1");
+ ImmutableClass immutable = new ImmutableClass(list);
+
+ // items 리스트를 직접 수정할 수 있음
+ List retrievedList = immutable.getItems();
+ retrievedList.add("item2"); // 외부에서 리스트 수정 가능
+ System.out.println(retrievedList); // [item1, item2]
+
+ // 원래 리스트도 수정됨
+ System.out.println(immutable.getItems()); // [item1, item2]
+}
+```
+
+3) 따라서 `방어적 복사`라는 것을 수행하라고 합니다. 가변 객체의 복사본을 저장하여 반환하는 방식입니다.
+```java
+public final class ImmutableClass {
+ private final List items;
+
+ public ImmutableClass(List items) {
+ this.items = new ArrayList<>(items); // 가변 리스트의 복사본을 저장
+ }
+
+ // 가변 객체의 복사본을 반환
+ public List getItems() {
+ return new ArrayList<>(items); // 외부에서 수정할 수 없도록 복사본 반환
+ }
+}
+
+```
+
+4) 이렇게 되면 아까와 달리 외부에서 직접 수정이 가능하지만, 이가 내부 필드에는 영향을 미치지 않게 되어 불변성이 보장됩니다.
+```java
+public static void main(String[] args) {
+ List list = new ArrayList<>();
+ list.add("item1");
+ ImmutableClass immutable = new ImmutableClass(list);
+
+ // items 리스트를 직접 수정할 수 있음
+ List retrievedList = immutable.getItems();
+ retrievedList.add("item2"); // 외부에서 리스트 수정 가능
+ System.out.println(retrievedList); // [item1, item2]
+
+ // 원래 리스트는 수정되지 않음
+ System.out.println(immutable.getItems()); // [item1]
+}
+```
+
+
+
+---
+
+### 🙌 함수형 프로그래밍을 통한 불변 클래스 제작
+제목과 같이 함수형 프로그래밍을 통한 불변 클래스를 제작할 수 있다.
+
+✅함수형 프로그래밍과 절차적/명령형 프로그래밍의 차이
+
+#### 함수형 프로그래밍
+- 인스턴스 자신은 수정하지 않고 새로운 인스턴스를 만들어 반환하는 방식을 사용한 것으로,
+실제 필드에는 영향이 없어 불변을 유지하는 프로그래밍 패턴
+- 불변이라는 점을 강조하기 위해 메서드 이름에도 동사 대신 전치사를 사용
+
+#### 절차적/명령형 프로그래밍
+- 인스턴스 자신을 수정하여 자신의 상태를 변화시키는 방식을 사용한 것으로,
+- 실제 필드에 영향이 있기에 불변을 유지하기는 어려운 프로그래밍 패턴
+
+
+
+### 🙋♀️ 그럼 불변 클래스의 단점은 없나요?
+다만 가변에 비해 성능(시간, 공간 문제)이 떨어지는 문제가 생길 수 있습니다.
+원하는 객체를 완성하기까지의 단계가 많고, 그 중간 단계에서 만들어진 객체들이 모두 버려진다면 성능 문제가 더 불거지게 됩니다.
+
+#### 1) 다단계 연산들을 예측하여 기본 기능으로 제공 (private 가변 동반 클래스를 활용)
+#### 2) 예측이 어렵다면, public 가변 동반 클래스로 제공
+
+하여 해당 단점을 보완해볼 수 있다.
+
+### 정리해보자면,
+1) 클래스는 꼭 필요한 경우가 아니라면 불변이어야 합니다.
+2) 불변으로 만들 수 없는 클래스라도 변경할 수 있는 부분을 최소한으로 줄여야 합니다.
+ 3) 다른 합당한 이유가 없다면 모두 `priavte final`을 사용하는 게 좋습니다.
+4) 생성자는 불변식 설정이 모두 완료된, 초기화가 완벽히 끝난 상태의 객체를 생성해야 합니다.
From c9fbc77dac646610611b61cffbb957ad61e9db88 Mon Sep 17 00:00:00 2001
From: yerim <97941141+yerim123456@users.noreply.github.com>
Date: Fri, 17 Jan 2025 00:04:44 +0900
Subject: [PATCH 6/9] =?UTF-8?q?refactor:=20=EC=96=B4=EB=AF=B8=20=ED=86=B5?=
=?UTF-8?q?=EC=9D=BC=20=EB=B0=8F=20=EC=98=A4=ED=83=80=20=EC=88=98=EC=A0=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
...34\354\206\214\355\231\224\355\225\264\353\235\274.md" | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git "a/3\354\236\245_\353\252\250\353\223\240_\352\260\235\354\262\264\354\235\230_\352\263\265\355\206\265_\353\251\224\354\204\234\353\223\234/\354\225\204\354\235\264\355\205\234 17/\353\263\200\352\262\275_\352\260\200\353\212\245\354\204\261\354\235\204_\354\265\234\354\206\214\355\231\224\355\225\264\353\235\274.md" "b/3\354\236\245_\353\252\250\353\223\240_\352\260\235\354\262\264\354\235\230_\352\263\265\355\206\265_\353\251\224\354\204\234\353\223\234/\354\225\204\354\235\264\355\205\234 17/\353\263\200\352\262\275_\352\260\200\353\212\245\354\204\261\354\235\204_\354\265\234\354\206\214\355\231\224\355\225\264\353\235\274.md"
index d486b10..5790e56 100644
--- "a/3\354\236\245_\353\252\250\353\223\240_\352\260\235\354\262\264\354\235\230_\352\263\265\355\206\265_\353\251\224\354\204\234\353\223\234/\354\225\204\354\235\264\355\205\234 17/\353\263\200\352\262\275_\352\260\200\353\212\245\354\204\261\354\235\204_\354\265\234\354\206\214\355\231\224\355\225\264\353\235\274.md"
+++ "b/3\354\236\245_\353\252\250\353\223\240_\352\260\235\354\262\264\354\235\230_\352\263\265\355\206\265_\353\251\224\354\204\234\353\223\234/\354\225\204\354\235\264\355\205\234 17/\353\263\200\352\262\275_\352\260\200\353\212\245\354\204\261\354\235\204_\354\265\234\354\206\214\355\231\224\355\225\264\353\235\274.md"
@@ -30,7 +30,7 @@
아래의 다섯 가지 규칙을 잘 따르면 됩니다.
#### 1) 객체의 상태를 변경하는 메서드를 제공하지 않는다.
-#### 2) 클래스를 확장할 수 없도록 한다. 하위 클래스에서 객체의 상태를 변하게 하는 것을 막아준다. (final 클래스로 정의 / 생성자를 private, protected로 정의)
+#### 2) 클래스를 확장할 수 없도록 한다. 하위 클래스에서 객체의 상태를 변하게 하는 것을 막아준다. (final 클래스로 정의 / 생성자를 private, package-private 정의)
#### 3) 모든 필드를 `final`로 선언한다. 불변으로 명시적으로 선언하여 설계자의 의도를 명확히 들어낸다.
#### 4) 모든 필드를 `private`로 선언한다. 필드가 참조하는 가변 객체를 클라이언트에서 직접 접근하여 수정하는 일을 막아준다. `public`으로 정의한 경우, 내부 표현을 쉽게 바꾸지 못하기에 `private`을 추천한다.
#### 5) 자신 외에는 내부의 가변 컴포넌트에 접근할 수 없도록 한다. 클래스에 가변 객체를 참조하고 있는 필드가 있다면, 클라이언트에서 그 객체를 변경할 수 있다.
@@ -108,7 +108,7 @@ public static void main(String[] args) {
---
### 🙌 함수형 프로그래밍을 통한 불변 클래스 제작
-제목과 같이 함수형 프로그래밍을 통한 불변 클래스를 제작할 수 있다.
+제목과 같이 함수형 프로그래밍을 통한 불변 클래스를 제작할 수 있습니다.
✅함수형 프로그래밍과 절차적/명령형 프로그래밍의 차이
@@ -130,9 +130,9 @@ public static void main(String[] args) {
#### 1) 다단계 연산들을 예측하여 기본 기능으로 제공 (private 가변 동반 클래스를 활용)
#### 2) 예측이 어렵다면, public 가변 동반 클래스로 제공
-하여 해당 단점을 보완해볼 수 있다.
+하여 해당 단점을 보완해볼 수 있습니다.
-### 정리해보자면,
+### 🙌 정리해보자면,
1) 클래스는 꼭 필요한 경우가 아니라면 불변이어야 합니다.
2) 불변으로 만들 수 없는 클래스라도 변경할 수 있는 부분을 최소한으로 줄여야 합니다.
3) 다른 합당한 이유가 없다면 모두 `priavte final`을 사용하는 게 좋습니다.
From 34a1e6abe7d7bc4fc3f0535a9df2cb8f31adc8f7 Mon Sep 17 00:00:00 2001
From: yerim <97941141+yerim123456@users.noreply.github.com>
Date: Sat, 18 Jan 2025 00:02:29 +0900
Subject: [PATCH 7/9] feat: Add item 12.md
---
...25\354\235\230\355\225\230\353\235\274.md" | 67 +++++++++++++++++++
1 file changed, 67 insertions(+)
create mode 100644 "3\354\236\245_\353\252\250\353\223\240_\352\260\235\354\262\264\354\235\230_\352\263\265\355\206\265_\353\251\224\354\204\234\353\223\234/\354\225\204\354\235\264\355\205\234 12/toString\354\235\200_\355\225\255\354\203\201_\354\236\254\354\240\225\354\235\230\355\225\230\353\235\274.md"
diff --git "a/3\354\236\245_\353\252\250\353\223\240_\352\260\235\354\262\264\354\235\230_\352\263\265\355\206\265_\353\251\224\354\204\234\353\223\234/\354\225\204\354\235\264\355\205\234 12/toString\354\235\200_\355\225\255\354\203\201_\354\236\254\354\240\225\354\235\230\355\225\230\353\235\274.md" "b/3\354\236\245_\353\252\250\353\223\240_\352\260\235\354\262\264\354\235\230_\352\263\265\355\206\265_\353\251\224\354\204\234\353\223\234/\354\225\204\354\235\264\355\205\234 12/toString\354\235\200_\355\225\255\354\203\201_\354\236\254\354\240\225\354\235\230\355\225\230\353\235\274.md"
new file mode 100644
index 0000000..b161067
--- /dev/null
+++ "b/3\354\236\245_\353\252\250\353\223\240_\352\260\235\354\262\264\354\235\230_\352\263\265\355\206\265_\353\251\224\354\204\234\353\223\234/\354\225\204\354\235\264\355\205\234 12/toString\354\235\200_\355\225\255\354\203\201_\354\236\254\354\240\225\354\235\230\355\225\230\353\235\274.md"
@@ -0,0 +1,67 @@
+## item 12
+
+### toString을 항상 재정의하라
+
+---
+
+### 🙋♀️ 왜 재정의하는 게 좋은가요?
+
+기본적인 `Object`의 `toString` 메서드를 사용한다면, 우리가 원하는 대로 문자열을 보통 반환하지 않는 다는 것을 알 수 있습니다.
+`PhoneNumber@abdbd` 처럼 `클래스_이름@16진수로_표시한_해시코드`를 반환할 뿐입니다.
+
+그래서 우리는 `toString` 일반 규약에 따라 `간결하면서 사람이 읽기 쉬운 형태의 유익한 정보`를 반환해줘야 합니다.
+또한 이는 `모든 하위 클래스에서 이 메서드를 재정의하라` 라고 표현될만큼 매우 강조되고 있습니다.
+
+결국 재정의를 하게 되면, 해당 클래스를 사용할 때`즐겁고, 디버깅하기 쉽`습니다.
+
+#### 예시 1) 오류 메세지 로깅
+우리가 작성한 객체를 참조하는 컴포넌트가 오류 메세지를 로깅할 때 `toString`은 자동으로 호출될 수 있습니다.
+이때 보다 쉽게 파악하기 위해 `toString`을 정의해둔다면 `보다 의미있는 메세지를 얻어갈 것`이기에 재정의하는 게 좋습니다.
+
+대부분 프로그래머들은 진단 메시지를
+```java
+System.out.println(phoneNumber + "에 연결할 수 없습니다.");
+```
+해당 방식으로 작성하게 됩니다. 재정의를 하지 않았다면 의미없는 메세지를 보게 되는 것입니다.
+
+#### 예시 2) 해당 객체를 포함하는 상황에서 출력을 진행
+이 객체를 포함하는 상황(ex `map 객체`)에 출력을 할 때 보다 의미있게 쓰이게 됩니다.
+`{Jenny=PhoneNumber@abdbd}`가 아닌 `{Jenny=707-867-5309}` 라는 의미있는 정보를 받게 될테니 말입니다.
+
+---
+
+### 🙋♀️ 그렇다면 어떻게 toString을 재정의해야 하나요?
+
+#### 1) 객체가 가진 주요 정보 모두를 반환하는 게 좋습니다.
+#### 2) `객체가 거대`하거나 `객체의 상태를 문자열로 표현하는 게 적합하지 않`다면 요약 정보를 담아서 합니다.
+#### 3) 반환값을 문서화할지 정합니다.
+
+---
+
+### 🙋♀️ 문서화할지 어떻게 정하나요?
+
+#### 1) 문서화의 장점
+표준적이고, 명확하고, 사람이 읽을 수 있게 됩니다.
+그렇기에 `그대로 입출력에 사용`하거나 `데이터 객체로 저장`하며 사용할 수 있습니다.
+
+따라서 문서화를 할것이라면, 명시한 포맷에 맞는 문자열과 객체를 상호 전환할 수 있는
+`정적 팩터리`나 `생성자`를 함께 제공해주면 좋습니다.
+
+#### 2) 문서화의 단점
+따라서 당연히 단점은 평생 그 포맷에 얽히게 된다는 점입니다.
+
+#### 결론
+그렇기에 명시하던 아니던, 의도는 명확히 밝혀야 합니다.
+포맷을 명시하려면, 아주 정확히, 포맷을 명시하지 않기로 했다면 `형식은 정해지지 않았으며 향후 변경될 수 있다`라는 문구를 추가해 명확히 달라질 수 있음을 이야기해야한다.
+
+### 🙌 주의점
+
+#### 1) 문서화 여부와 상관없이 toString이 반환한 값에 포함된 정보를 얻어올 수 있는 API를 제공하는 게 좋습니다.
+포맷이 되었다고 해서 해당 값에 접근할 수 있는 `getter` 가 없어서 `toString`에서 값을 파싱하는 건 성능이 나빠지고 필요하지도 않은 작업입니다.
+향후 포맷이 변경되면 이는 시스템이 망가지는 결과를 초래하기에 `getter`를 지원해주는 게 중요합니다.
+
+#### 2) 정적 유틸리티 클래스는 toString 제공할 필요 X
+#### 3) 대부분의 열거 타입도 자바가 이미 완벽한 toString 제공하니 따로 제공할 필요 X
+#### 4) 상위 클래스에서 이미 잘 재정의된 toString 이 있다면 제공할 필요 X
+#### 5) 다만!! 하위 클래스들이 공유해야할 문자열 표현이 있는 추상 클래스에선 정의 필요!!
+#### 6) AutoValue 프레임워크는 toString을 생성해주지만, 클래스의 의미가 중요한 경우 사용하지 않는 것이 좋음(ex PhoneNumber는 형식에 맞춰 반환 필요 / Potion은 자동 생성에 적합)
From 47e29b4b9e21f090851f30e3707462f3eabe32c9 Mon Sep 17 00:00:00 2001
From: yerim <97941141+yerim123456@users.noreply.github.com>
Date: Sat, 18 Jan 2025 00:03:12 +0900
Subject: [PATCH 8/9] remove: Delete item 11.md
---
...25\354\235\230\355\225\230\353\235\274.md" | 86 -------------------
1 file changed, 86 deletions(-)
delete mode 100644 "3\354\236\245_\353\252\250\353\223\240_\352\260\235\354\262\264\354\235\230_\352\263\265\355\206\265_\353\251\224\354\204\234\353\223\234/\354\225\204\354\235\264\355\205\234 11/equals\353\245\274_\354\236\254\354\240\225\354\235\230\355\225\230\353\240\244\352\261\260\353\223\240_hashCode\353\217\204_\354\236\254\354\240\225\354\235\230\355\225\230\353\235\274.md"
diff --git "a/3\354\236\245_\353\252\250\353\223\240_\352\260\235\354\262\264\354\235\230_\352\263\265\355\206\265_\353\251\224\354\204\234\353\223\234/\354\225\204\354\235\264\355\205\234 11/equals\353\245\274_\354\236\254\354\240\225\354\235\230\355\225\230\353\240\244\352\261\260\353\223\240_hashCode\353\217\204_\354\236\254\354\240\225\354\235\230\355\225\230\353\235\274.md" "b/3\354\236\245_\353\252\250\353\223\240_\352\260\235\354\262\264\354\235\230_\352\263\265\355\206\265_\353\251\224\354\204\234\353\223\234/\354\225\204\354\235\264\355\205\234 11/equals\353\245\274_\354\236\254\354\240\225\354\235\230\355\225\230\353\240\244\352\261\260\353\223\240_hashCode\353\217\204_\354\236\254\354\240\225\354\235\230\355\225\230\353\235\274.md"
deleted file mode 100644
index 1b07c96..0000000
--- "a/3\354\236\245_\353\252\250\353\223\240_\352\260\235\354\262\264\354\235\230_\352\263\265\355\206\265_\353\251\224\354\204\234\353\223\234/\354\225\204\354\235\264\355\205\234 11/equals\353\245\274_\354\236\254\354\240\225\354\235\230\355\225\230\353\240\244\352\261\260\353\223\240_hashCode\353\217\204_\354\236\254\354\240\225\354\235\230\355\225\230\353\235\274.md"
+++ /dev/null
@@ -1,86 +0,0 @@
-## item 11
-
-### equals를 재정의하려거든 hashCode도 재정의하라
-
----
-
-### 🙋♀️ 왜 함께 재정의해줘야 하나요?
-
-`hashCode` 일반 규약을 어기게 되어 해당 클래스의 인스턴스를 `HashMap`이나 `HashSet` 같은 컬렉션의 원소로 사용할 때 문제를 일으킬 것이기 때문입니다.
-
----
-
-### 🙋 hashCode 의 일반 규약은 무엇인가요?
-다음은 규약 중 일부입니다.
-#### 1. equals 비교에 사용되는 핵심 필드가 달라지지 않았다면, hashCode 메서드는 몇 번을 호출해도 일관되게 항상 같은 값을 반환해야 합니다.
-#### 2. equals 비교를 통해 같다고 판명된 객체라면, 각 객체의 hashCode는 똑같은 값을 반환해야 합니다.
-#### 3. equals 비교를 통해 다르다고 판단된 값이라도, 서로 다른 값을 반환할 필요는 없습니다. 다만!! 다른 객체라면 다른 값을 반환하는 게 해시테이블의 성능이 좋아집니다.
-
----
-
-### 🙌 hashCode 재정의를 잘못한다면 2번 조항에서 문제가 생깁니다.
-간단히 말하자면, `equals`에서는 같은 객체라고 판단했으나 `hashCode`에 대한 재정의가 잘못되어서 `HashMap`이나 `HashSet`에서 같은 원소로 판별되지 않는 문제가 생긴다는 것입니다.
-
-`equals`는 물리적으로 다른 두 객체를 논리적으로 같은 객체라고 판단할 수 있지만 `hashCode`를 재정의하지 않는다면 `hashCode`는 이를 모를 것이기 때문입니다.
-
----
-
-### 🙋♀️ 그럼 hashCode는 어떻게 구현하는 게 올바른 방법인가요?
-
-#### 최악의 방법
-```java
-@Override
-public int hashCode(){
- return 42;
-}
-```
-`동치인` 모든 객체에서 똑같은 해시코드를 반환하기에 적법합니다.
-문제는 `동치가 아닌` 객체에서도 똑같은 해시코드를 반환하기 때문에 생깁니다.
-결과적으로 해시테이블의 버킷 하나에 모두 담겨 연결 리스트처럼 동작하고, 평균 수행 시간이 0(1) > O(n)으로 느려져서 객체가 많아지면 도저히 쓸 수 없게 됩니다.
-
----
-
-#### 좋은 방법
-```java
-@Override
-public int hashCode(){
- int result = Short.hashCode(areaCode);
- result = 31 * result + Short.hashCode(prefix);
- result = 31 * result + Short.hashCode(lineNum);
- return result;
-}
-```
-좋은 해시 함수라면 서로 다른 인스턴스에 다른 해시코드를 반환합니다.(3번 조항)
-##### 1) int 변수 result를 선언한 후 `첫번째 핵심 필드`를 단계 `2.a 방식으로 계산`한 해시코드로 초기화합니다.
-##### 2) 해당 객체의 나머지 핵심 필드에 대한 작업을 수행합니다.
-| 필드 형식 및 조건 | 처리 방식 |
-|--------------------------|------------------------------------------------------------------------------|
-| 기본 타입 | `Type.hashCode(f)` |
-| 참조 타입 + equals 재귀 호출 처리 | 해당 필드의 `hashCode` 재귀 호출 / 필드의 표준형 제작 |
-| 배열 | 배열의 참조값이 아닌 각 핵심 원소에 대한 값을 처리하며 갱신(누적) / 모든 원소가 핵심 원소라면, Arrays.hashCode를 사용 |
-
-#### 3) 계산한 해시코드로 result 갱신
-#### 4) result 반환
-#### 5) 동치인 인스턴스에 대해 똑같은 해시 코드를 반환하는지 테스트
-#### 6) 단위 테스트 작성
-
----
-
-✔ 추가 주의점
-#### 1) null, 핵심 원소 X 배열 > 상수, 특히 0으로 처리하기
-#### 2) 파생 필드는 계산에서 제외하기
-#### 3) equals 비교에 사용되지 않은 필드 반드시 제외하기
-#### 4) result와 곱하는 수는 짝수이거나 오버플로가 발생하면 안됨(31 추천)
-#### 5) 성능 개선 때문에 핵심 필드 생략을 해선 안됨, 되레 속도가 느려질 가능성 있음
-
----
-
-✔ 추가 개선 사항
-#### 1) 코드를 줄이기 위해 hash 메서드를 사용할 수 있으나 성능에 민감하지 않은 상황에서만 사용하기
-#### 2) 클래스가 불변, 해시코드를 계산하는 비용이 크다면 캐싱을 고려(해당 타입의 객체가 해시의 키로 사용)
-#### 3) 해시의 키로 사용되지 않는다면,지연 초기화 전략 사용
-#### 4) hashCode가 반환하는 값의 생성 규칙을 API 사용자에게 자세히 공표하지 말기
-
-이에 따라서 핵심 필드 3개만을 사용하여 간단히 계산이 가능해졌습니다.
-
----
From d0e5d8063191965281f26a898edfb48ee0982d6c Mon Sep 17 00:00:00 2001
From: 023
Date: Mon, 20 Jan 2025 10:15:03 +0900
Subject: [PATCH 9/9] =?UTF-8?q?Rename=20clone=20=EC=9E=AC=EC=A0=95?=
=?UTF-8?q?=EC=9D=98=EB=8A=94=20=EC=A3=BC=EC=9D=98=ED=95=B4=EC=84=9C=20?=
=?UTF-8?q?=EC=A7=84=ED=96=89=ED=95=98=EB=9D=BC.md=20to=20clone=5F?=
=?UTF-8?q?=EC=9E=AC=EC=A0=95=EC=9D=98=EB=8A=94=5F=EC=A3=BC=EC=9D=98?=
=?UTF-8?q?=ED=95=B4=EC=84=9C=5F=EC=A7=84=ED=96=89=ED=95=98=EB=9D=BC.md?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
...4\204\234_\354\247\204\355\226\211\355\225\230\353\235\274.md" | 0
1 file changed, 0 insertions(+), 0 deletions(-)
rename "3\354\236\245_\353\252\250\353\223\240_\352\260\235\354\262\264\354\235\230_\352\263\265\355\206\265_\353\251\224\354\204\234\353\223\234/\354\225\204\354\235\264\355\205\234 13/clone \354\236\254\354\240\225\354\235\230\353\212\224 \354\243\274\354\235\230\355\225\264\354\204\234 \354\247\204\355\226\211\355\225\230\353\235\274.md" => "3\354\236\245_\353\252\250\353\223\240_\352\260\235\354\262\264\354\235\230_\352\263\265\355\206\265_\353\251\224\354\204\234\353\223\234/\354\225\204\354\235\264\355\205\234 13/clone_\354\236\254\354\240\225\354\235\230\353\212\224_\354\243\274\354\235\230\355\225\264\354\204\234_\354\247\204\355\226\211\355\225\230\353\235\274.md" (100%)
diff --git "a/3\354\236\245_\353\252\250\353\223\240_\352\260\235\354\262\264\354\235\230_\352\263\265\355\206\265_\353\251\224\354\204\234\353\223\234/\354\225\204\354\235\264\355\205\234 13/clone \354\236\254\354\240\225\354\235\230\353\212\224 \354\243\274\354\235\230\355\225\264\354\204\234 \354\247\204\355\226\211\355\225\230\353\235\274.md" "b/3\354\236\245_\353\252\250\353\223\240_\352\260\235\354\262\264\354\235\230_\352\263\265\355\206\265_\353\251\224\354\204\234\353\223\234/\354\225\204\354\235\264\355\205\234 13/clone_\354\236\254\354\240\225\354\235\230\353\212\224_\354\243\274\354\235\230\355\225\264\354\204\234_\354\247\204\355\226\211\355\225\230\353\235\274.md"
similarity index 100%
rename from "3\354\236\245_\353\252\250\353\223\240_\352\260\235\354\262\264\354\235\230_\352\263\265\355\206\265_\353\251\224\354\204\234\353\223\234/\354\225\204\354\235\264\355\205\234 13/clone \354\236\254\354\240\225\354\235\230\353\212\224 \354\243\274\354\235\230\355\225\264\354\204\234 \354\247\204\355\226\211\355\225\230\353\235\274.md"
rename to "3\354\236\245_\353\252\250\353\223\240_\352\260\235\354\262\264\354\235\230_\352\263\265\355\206\265_\353\251\224\354\204\234\353\223\234/\354\225\204\354\235\264\355\205\234 13/clone_\354\236\254\354\240\225\354\235\230\353\212\224_\354\243\274\354\235\230\355\225\264\354\204\234_\354\247\204\355\226\211\355\225\230\353\235\274.md"