본문 바로가기
개발 공부/Java

이펙티브 자바 아이템 10 - equals 는 일반 규약을 지켜 재정의하라 - 완벽 공략

by 개발인생 2022. 10. 24.
반응형

아이템 10 - equals 는 일반 규약을 지켜 재정의하라 - 완벽 공략

이 글은 백기선 님의 이펙티브 자바 강의와 이펙티브 자바 3 / E 편을 참고하여 작성하였습니다.

Value 기반 클래스

value object, 혹은 값 클래스라고도 한다.

DDD 에서 나오는 value object 나 값처럼 사용이되는 클래스나 객체를 의미한다.

값 클래스란 int 와 String 처럼 값을 표현하는 클래스를 말한다.

값 클래스는 객체의 유일성을 판단하기 위한 식별자가 없다.

그 클래스의 인스턴스가 가지고 있는 필드의 값들이 그 오브젝트를 대변하게 된다.

public class Point {
   private final int x;
   private final int y;

   public Point(int x, int y) {
      this.x = x;
      this.y = y;
   }

   @Override public boolean equals(Object o) {
      if (this == o) {
         return true;
      }

      if (!(o instanceof Point)) {
         return false;
      }

      Point p = (Point) o;
      return p.x == x && p.y == y;
   }

   // 아이템 11 참조
   @Override public int hashCode()  {
      return 31 * x + y;
   }
}

final 키워드를 사용하여 Value 기반 클래스를 생성할 수 있다.

   private final int x;
   private final int y;

final 키워드를 써서 한번 값을 받고 난 뒤에는 변경이 뒤지 않도록 만든다.

그 뒤, equals, hashCode, toString 을 재정의한다.

주의할 점은 id 같이 해당 객체를 식별하는 값이 있으면 안된다.

public record Point(int x, int y) {
}

자바 17버전부터 추가된 Record 를 사용하는 방법이다.

public class PointRecord {
   public static void main(String[] args) {
      Point p1 = new Point(1, 0);
      Point p2 = new Point(1, 0);

      System.out.println(p1.equals(p2));
   }
}

Record 를 사용하면 자바 컴파일시 equals, hashCode, toString 를 구현해준다.

즉, Record 를 사용하면 equals, hashCode, toString 을 재정의할 필요가 없다.

물론 Record 안에 메서드를 정의하는 것 또한 가능하다.

public class PointRecord {
   public static void main(String[] args) {
      Point p1 = new Point(1, 0);
      Point p2 = new Point(1, 0);

      System.out.println(p1.x());
      System.out.println(p1.y());
   }
}

Record 인스턴스를 만들면 값을 변경할 수 없다.

값을 꺼낼때는 위의 코드처럼 필드명() 으로 꺼내 사용한다.


StackOverFlowError

StackOverFlowError 를 이해하려면 Stack 메모리Heap 메모리 를 알아야한다.

Stack 메모리 는 한 스레드마다 쓸 수 있는 메모리 공간이다.

Stack 메모리 에는 Stack 프레임 이 벽돌처럼 쌓이게 된다.

Stack 프레임LIFO (Last In First Out) 로 처리된다.

Stack 프레임 은 메서드를 호출 할 때 쌓이게된다.

Stack 프레임 안에는 메서드를 호출 할 때 넘겨줬던 매개변수, 메서드에서 참조하는 객체들의 레퍼런스

그리고 메서드 실행이 끝났을 때 어디로 되돌아가야 는 지에 대한 정보가 있다.

Stack 메모리 안에 계속 Stack 프레임이 쌓여 가용치를 넘어가게 되면 StackOverFlowError 가 발생하게된다.

StackOverFlowError 는 더이상 Stack 프레임을 쌓을 수 없다는 에러이다.

Heap 메모리 는 객체들이 있는 공간이다.

가비지 컬렉터가 정리해주는 공간이 Heap 메모리 이다.

Heap 메모리 안에 객체들이 있고 객체들이 가르키는 레퍼런스는 Stack 메모리 에 있다.

mac 이나 리눅스 같은 경우에는 Stack 메모리 의 사이즈가 1MB 로 설정되어 있따.

Stack 메모리 의 사용량이 많은 프로그램이라면 자바 실행시 -Xss 옵션을 통해 조정이 가능하다.


리스코프 치환 원칙

리스코프 치환 원칙은 객체 지향 5대 원칙 SOLID 중의 하나이다.

리스코프 치환 원칙은 상속 구조에서의 이야기이다.

원래 상위 클래스 타입의 인스턴스를 넘겨주던 코드는 상위 클래스 대신의 그 어떠한 하위 클래스 타입의 인스턴스가 넘겨오더라도 동일하게 동작해야한다는 원칙이다.

상속구조에서 의미를 유지할 수 있도록 하위 클래스에서 어떤 행동을 재정의할 때 (equals 구현 등)

리스코프 치환 원칙을 꺠뜨리지 않도록 주의해야한다.

반응형

댓글