Java

[Effective Java] 4-4. 클래스와 인터페이스: 클래스

noahkim_ 2024. 12. 27. 21:37

조슈아 블로크 님의 "Effective Java" 책을 정리한 포스팅 입니다.


1. 태그 달린 클래스보다는 클래스 계층구조를 활용하라

태그 달린 클래스

public class Shape {
    // 태그 필드
    public enum ShapeType { CIRCLE, RECTANGLE }
    private final ShapeType type;

    // CIRCLE에만 필요한 필드
    private double radius;

    // RECTANGLE에만 필요한 필드
    private double width;
    private double height;

    // 생성자: 원
    public Shape(double radius) {
        this.type = ShapeType.CIRCLE;
        this.radius = radius;
    }

    // 생성자: 직사각형
    public Shape(double width, double height) {
        this.type = ShapeType.RECTANGLE;
        this.width = width;
        this.height = height;
    }

    // 넓이를 계산하는 메서드
    public double area() {
        switch (type) {
            case CIRCLE:
                return Math.PI * radius * radius;
            case RECTANGLE:
                return width * height;
            default:
                throw new UnsupportedOperationException("Unknown shape type");
        }
    }
}
  • 하위 클래스를 표시하는 값
  • 클래스 계층구조를 흉내냄

 

단점
  • 쓸데없는 코드가 많음
    • 여러 구현이 한 클래스에 혼합되어 있음
  • 가독성이 나쁨
  • 오류를 내기 쉬움

 

클래스 계층구조

추상클래스 정의
  • 루트가 될 
  • 태그 값에 따라 동작이 달라지는 메서드들을 추상 메서드로 정의

 

서브클래스 정의
  • 가가자의 의미에 해당하는 데이터 필드를 넣음
  • 루트 클래스가 정의한 추상 메서드를 각자의 의미에 맞게 구현

 

2. 멤버 클래스는 되도록 static으로 선언하라

중첩 클래스

  • 다른 클래스 안에 정의된 클래스

 

정적 멤버 클래스
  • 외부 클래스와 독립적
    • 외부 클래스의 참조를 가지지 않아 메모리 누수가 방지됨
    • 외부 클래스의 static 멤버만 접근 가능
  • 관련 있는 클래스들을 논리적으로 묶기 위해 사용됨
  • 사용 예
    • Map.Entry: 논리적으로 묶고, Map과는 독립적으로 두어 외부 참조를 가지지 않도록 함

 

멤버 클래스
  • 바깥 클래스의 인스턴스와 암묵적으로 연결됨
    • 바깥 클래스의 모든 멤버에 접근 가능
    • 바깥 인스턴스로의 숨은 외부 참조를 가지게 됨
    • 이로 인해 메모리 누수가 날 수 있음
  • 사용 예
    • 어댑터를 정의할 때 자주 쓰임
    • 자신의 반복자 구현

 

익명 클래스
  • 쓰이는 시점에 선언과 동시에 인스턴스가 만들어짐
  • 람다로 대체됨

 

지역 클래스
  • 지역 변수가 선언되는 공간에 선언된 클래스

 

3. 톱레벨 클래스는 한 파일에 하나만 담으라