Effective Java 4강 ITEM24 맴버 클래스는 되도록 static으로 만들라 - 1

park geonwoo·2024년 10월 28일

Effective Java

목록 보기
27/56

이 주제는 자바(Java) 프로그래밍에서 중요한 설계 결정 중 하나로, 클래스의 구조와 동작에 큰 영향을 미칠 수 있습니다. 아래에서 맴버 클래스의 개념, static 맴버 클래스와 non-static 맴버 클래스의 차이점, 각각의 장단점, 그리고 언제 static으로 선언하는 것이 적절한지에 대해 자세히 살펴보겠습니다.


목차

  1. [맴버 클래스란?]
  2. [맴버 클래스의 종류]
    • [2.1. 정적 맴버 클래스(Static Nested Class)]
    • [2.2. 내부 클래스(Inner Class)]
      • [2.2.1. 인스턴스 내부 클래스(Non-Static Inner Class)]
      • [2.2.2. 지역 내부 클래스(Local Inner Class)]
      • [2.2.3. 익명 내부 클래스(Anonymous Inner Class)]
  3. [정적 맴버 클래스와 비정적 맴버 클래스의 비교]
  4. [맴버 클래스를 정적으로 만드는 이유]
  5. [맴버 클래스를 정적으로 만들지 않아야 하는 경우]
  6. [맴버 클래스를 정적으로 만들지 않아야 하는지 결정하는 기준]
  7. [구체적인 예제]
    • [7.1. 정적 맴버 클래스 예제]
    • [7.2. 비정적 맴버 클래스 예제]
  8. [맴버 클래스를 static으로 만드는 것의 장단점]
  9. [맴버 클래스 설계 시 고려사항]
  10. [결론]

1. 맴버 클래스란?

  • 맴버 클래스(Member Class)는 다른 클래스의 내부에 정의된 클래스를 말합니다. 자바에서는 이를 중첩 클래스(Nested Class)라고도 부릅니다. 맴버 클래스는 외부 클래스의 멤버(필드, 메서드 등)처럼 취급되며, 외부 클래스와 밀접한 관련이 있는 클래스를 논리적으로 그룹화할 때 유용하게 사용됩니다.

2. 맴버 클래스의 종류

자바에서는 맴버 클래스를 크게 두 가지로 분류할 수 있습니다:

  1. 정적 맴버 클래스(Static Nested Class)
  2. 내부 클래스(Inner Class)

2.1. 정적 맴버 클래스 (Static Nested Class)

  • 정의: 외부 클래스의 static으로 선언된 중첩 클래스.
  • 특징:
    • 외부 클래스의 인스턴스와 독립적으로 존재.
    • 외부 클래스의 static 멤버에만 직접 접근 가능.
    • 외부 클래스의 인스턴스 멤버에는 OuterClass.this를 통해 접근해야 함.
  • 용도: 외부 클래스와 논리적으로 관련되지만, 외부 클래스의 인스턴스와는 독립적인 클래스를 정의할 때 사용.

2.2. 내부 클래스 (Inner Class)

내부 클래스는 외부 클래스의 인스턴스와 밀접하게 연관된 클래스입니다. 내부 클래스는 다시 세 가지로 분류됩니다:

2.2.1. 인스턴스 내부 클래스 (Non-Static Inner Class)

  • 정의: static 키워드가 없는 중첩 클래스.
  • 특징:
    • 외부 클래스의 인스턴스와 밀접하게 연관.
    • 외부 클래스의 모든 멤버(인스턴스 및 static)에 접근 가능.
    • 외부 클래스의 인스턴스가 필요.
  • 용도: 외부 클래스의 인스턴스와 함께 존재해야 하는 클래스를 정의할 때 사용.

2.2.2. 지역 내부 클래스 (Local Inner Class)

  • 정의: 메서드나 초기화 블록 내에 정의된 클래스.
  • 특징:
    • 메서드가 실행될 때 생성되고, 메서드가 종료되면 소멸.
    • 메서드 내의 지역 변수에 접근할 수 있으나, 지역 변수는 final 또는 effectively final이어야 함.
  • 용도: 특정 메서드 내에서만 사용되는 보조 클래스를 정의할 때 사용.

2.2.3. 익명 내부 클래스 (Anonymous Inner Class)

  • 정의: 이름이 없는 내부 클래스.
  • 특징:
    • 단일 인스턴스를 만들기 위해 사용.
    • 주로 인터페이스나 추상 클래스를 구현할 때 사용.
  • 용도: 이벤트 핸들러, 콜백 등에서 간단한 구현을 제공할 때 사용.

3. 정적 맴버 클래스와 비정적 맴버 클래스의 비교

특징정적 맴버 클래스(Static Nested Class)비정적 맴버 클래스(Inner Class)
외부 클래스의 인스턴스필요 없음필요함
접근성외부 클래스의 static 멤버에만 직접 접근 가능외부 클래스의 모든 멤버에 접근 가능
메모리 사용외부 클래스의 인스턴스와 독립적으로 메모리 사용외부 클래스의 인스턴스와 함께 메모리 사용
인스턴스 생성 방법외부 클래스의 인스턴스 없이도 생성 가능외부 클래스의 인스턴스를 통해서만 생성 가능
용도외부 클래스와 논리적으로 관련되지만, 외부 클래스의 인스턴스와 독립적인 클래스외부 클래스의 인스턴스와 밀접하게 연관된 클래스

요약

  • 정적 맴버 클래스는 외부 클래스의 인스턴스와 독립적으로 존재하며, 외부 클래스의 static 멤버에만 직접 접근할 수 있습니다.
  • *비정적 맴버 클래스(Inner Class)**는 외부 클래스의 인스턴스와 밀접하게 연관되며, 외부 클래스의 모든 멤버에 접근할 수 있습니다.

4. 맴버 클래스를 정적으로 만드는 이유

맴버 클래스를 static으로 만드는 주요 이유는 다음과 같습니다:

4.1. 메모리 효율성 향상

  • 독립적인 존재: 정적 맴버 클래스는 외부 클래스의 인스턴스와 독립적으로 존재하기 때문에, 외부 클래스의 인스턴스를 참조할 필요가 없어 메모리 사용량을 줄일 수 있습니다.
  • 메모리 절약: 비정적 맴버 클래스는 외부 클래스의 인스턴스 참조를 포함하기 때문에, 메모리 사용량이 증가할 수 있습니다. 정적 맴버 클래스를 사용하면 이러한 비용을 피할 수 있습니다.

4.2. 캡슐화 강화

  • 독립적 접근: 정적 맴버 클래스는 외부 클래스의 인스턴스에 직접 접근할 필요가 없기 때문에, 외부 클래스의 인스턴스 상태를 보호하고, 캡슐화를 강화할 수 있습니다.

4.3. 코드의 명확성 및 가독성 향상

  • 논리적 그룹화: 정적 맴버 클래스를 사용하면, 외부 클래스와 관련된 클래스를 논리적으로 그룹화하여 코드의 가독성을 높일 수 있습니다.
  • 명확한 의도: 정적 맴버 클래스는 외부 클래스의 인스턴스와 독립적으로 설계되었음을 명확하게 나타냅니다.

4.4. 상속 및 다형성

  • 유연한 설계: 정적 맴버 클래스는 외부 클래스의 상속 계층과 독립적으로 설계할 수 있어, 상속과 다형성을 더욱 유연하게 활용할 수 있습니다.

5. 맴버 클래스를 정적으로 만들지 않아야 하는 경우

맴버 클래스를 static으로 만들지 않아야 하는 주요 경우는 다음과 같습니다:

5.1. 외부 클래스의 인스턴스 멤버에 접근해야 할 때

  • 필요성: 비정적 맴버 클래스는 외부 클래스의 인스턴스 멤버(필드, 메서드 등)에 직접 접근할 수 있습니다. 외부 클래스의 인스턴스 상태에 의존하는 기능을 구현해야 하는 경우 비정적 맴버 클래스를 사용해야 합니다.

5.2. 외부 클래스의 인스턴스와 밀접한 관련이 있을 때

  • 상호 의존성: 비정적 맴버 클래스는 외부 클래스의 인스턴스와 밀접하게 연관된 작업을 수행할 때 유용합니다. 예를 들어, 외부 클래스의 상태를 기반으로 동작하는 클래스를 정의할 때 비정적 맴버 클래스를 사용하는 것이 적합합니다.

5.3. 내부 클래스가 외부 클래스의 인스턴스 데이터를 필요로 할 때

  • 데이터 공유: 비정적 맴버 클래스는 외부 클래스의 인스턴스 데이터를 직접 참조하고 사용할 수 있기 때문에, 외부 클래스의 데이터를 활용하는 데 유리합니다.

6. 맴버 클래스를 정적으로 만들지 않아야 하는지 결정하는 기준

맴버 클래스를 static으로 만들지 여부를 결정할 때 고려해야 할 주요 기준은 다음과 같습니다:

6.1. 외부 클래스의 인스턴스에 접근이 필요한가?

  • 필요하다면 비정적: 내부 클래스가 외부 클래스의 인스턴스 필드나 메서드에 접근해야 한다면 비정적 맴버 클래스로 선언해야 합니다.
  • 필요 없다면 정적: 내부 클래스가 외부 클래스의 인스턴스와 독립적으로 동작할 수 있다면 정적 맴버 클래스로 선언하는 것이 좋습니다.

6.2. 내부 클래스의 사용 용도가 외부 클래스의 인스턴스와 독립적인가?

  • 독립적이라면 정적: 내부 클래스가 외부 클래스의 인스턴스와 독립적으로 사용될 수 있다면 정적 맴버 클래스로 선언합니다.
  • 의존적이라면 비정적: 내부 클래스가 외부 클래스의 인스턴스에 의존적이라면 비정적 맴버 클래스로 선언합니다.

6.3. 내부 클래스가 외부 클래스의 인스턴스와 함께 존재해야 하는가?

  • 함께 존재해야 한다면 비정적: 내부 클래스가 외부 클래스의 인스턴스와 함께 존재해야 하는 경우 비정적 맴버 클래스로 선언합니다.
  • 독립적으로 존재해도 된다면 정적: 내부 클래스가 외부 클래스의 인스턴스와 독립적으로 존재할 수 있다면 정적 맴버 클래스로 선언합니다.

6.4. 메모리 및 성능 고려

  • 메모리 절약을 원한다면 정적: 정적 맴버 클래스는 외부 클래스의 인스턴스 참조를 포함하지 않기 때문에 메모리 사용을 절약할 수 있습니다.
  • 외부 클래스의 인스턴스와 함께 사용되며, 메모리 사용이 문제가 되지 않는다면 비정적: 만약 외부 클래스의 인스턴스와 함께 사용되며, 메모리 사용이 큰 문제가 되지 않는다면 비정적 맴버 클래스로 선언할 수 있습니다.

7. 구체적인 예제

7.1. 정적 맴버 클래스 예제

상황: Outer 클래스는 Inner 클래스를 포함하고 있으며, Inner 클래스는 Outer 클래스의 static 멤버만 접근합니다.

public class Outer {
    private static String staticField = "Static Field";
    private String instanceField = "Instance Field";

    // 정적 맴버 클래스
    public static class Inner {
        public void print() {
            // 외부 클래스의 static 멤버에 접근 가능
            System.out.println("Accessing: " + staticField);

            // 외부 클래스의 인스턴스 멤버에는 직접 접근 불가능
            // System.out.println("Accessing: " + instanceField); // 오류 발생
        }
    }

    public static void main(String[] args) {
        // 정적 맴버 클래스의 인스턴스 생성
        Outer.Inner inner = new Outer.Inner();
        inner.print(); // 출력: Accessing: Static Field
    }
}

설명:

  • Inner 클래스는 static으로 선언되어 있어 Outer 클래스의 인스턴스 없이도 생성할 수 있습니다.
  • Inner 클래스는 Outer 클래스의 static 멤버인 staticField에 접근할 수 있지만, 인스턴스 멤버인 instanceField에는 직접 접근할 수 없습니다.

7.2. 비정적 맴버 클래스 예제

상황: Outer 클래스는 Inner 클래스를 포함하고 있으며, Inner 클래스는 Outer 클래스의 인스턴스 멤버에 접근합니다.

public class Outer {
    private static String staticField = "Static Field";
    private String instanceField = "Instance Field";

    // 비정적 맴버 클래스 (Inner Class)
    public class Inner {
        public void print() {
            // 외부 클래스의 모든 멤버에 접근 가능
            System.out.println("Accessing: " + staticField);
            System.out.println("Accessing: " + instanceField);
        }
    }

    public static void main(String[] args) {
        Outer outer = new Outer();
        // 비정적 맴버 클래스의 인스턴스 생성
        Outer.Inner inner = outer.new Inner();
        inner.print();
        /*
            출력:
            Accessing: Static Field
            Accessing: Instance Field
        */
    }
}

설명:

  • Inner 클래스는 static으로 선언되지 않았기 때문에, Outer 클래스의 인스턴스를 통해서만 생성할 수 있습니다.
  • Inner 클래스는 Outer 클래스의 모든 멤버(staticinstance)에 접근할 수 있습니다.

8. 맴버 클래스를 static으로 만드는 것의 장단점

8.1. 장점

  1. 메모리 효율성 향상:
    • 정적 맴버 클래스는 외부 클래스의 인스턴스 참조를 포함하지 않기 때문에, 메모리 사용량을 줄일 수 있습니다.
  2. 캡슐화 강화:
    • 외부 클래스의 인스턴스와 독립적으로 존재하므로, 외부 클래스의 인스턴스 상태를 보호할 수 있습니다.
  3. 명확한 의도:
    • 내부 클래스가 외부 클래스의 인스턴스에 의존하지 않음을 명확하게 나타낼 수 있습니다.
  4. 성능 향상:
    • 정적 맴버 클래스는 인스턴스 내부 클래스로 생성될 때의 추가적인 참조 비용을 피할 수 있습니다.
  5. 유연한 상속:
    • 정적 맴버 클래스는 외부 클래스와 독립적으로 상속받거나 확장할 수 있습니다.

8.2. 단점

  1. 외부 클래스의 인스턴스에 접근 불가:
    • 정적 맴버 클래스는 외부 클래스의 인스턴스 멤버에 직접 접근할 수 없어, 필요한 경우 OuterClass.this와 같은 참조가 필요할 수 있습니다.
  2. 코드 복잡성 증가 가능:
    • 특정 상황에서 외부 클래스의 인스턴스 멤버에 접근하기 위해 추가적인 코드를 작성해야 할 수 있습니다.
  3. 무관한 경우 사용 시 혼란:
    • 외부 클래스와 상관없는 용도로 정적 맴버 클래스를 사용하면, 코드의 의도가 명확하지 않을 수 있습니다.

9. 맴버 클래스 설계 시 고려사항

맴버 클래스를 설계할 때는 다음과 같은 사항들을 고려해야 합니다:

9.1. 클래스의 책임과 역할

  • 논리적 그룹화: 맴버 클래스가 외부 클래스와 논리적으로 관련이 있는지 평가합니다.
  • 책임 분리: 맴버 클래스가 외부 클래스의 기능을 보완하거나 특정 기능을 분리하는 역할을 하는지 확인합니다.

9.2. 캡슐화와 정보 은닉

  • 접근 제어자: 맴버 클래스의 접근 제어자를 적절히 설정하여, 외부에서 불필요하게 접근하지 못하도록 합니다.
  • 정보 은닉: 맴버 클래스가 외부 클래스의 내부 구현에 의존하지 않도록 설계합니다.

9.3. 유지보수성과 확장성

  • 독립적 변경 가능성: 맴버 클래스가 외부 클래스와 독립적으로 변경될 수 있는지 평가합니다.
  • 재사용성: 맴버 클래스가 다른 클래스에서도 재사용될 가능성이 있는지 고려합니다.

9.4. 상속과 다형성

  • 상속의 필요성: 맴버 클래스가 외부 클래스의 기능을 상속받거나 확장할 필요가 있는지 평가합니다.
  • 인터페이스 구현: 맴버 클래스가 특정 인터페이스를 구현하여 다형성을 활용할 수 있는지 고려합니다.

9.5. 성능 고려

  • 인스턴스 생성 비용: 맴버 클래스의 인스턴스 생성이 성능에 미치는 영향을 평가합니다.
  • 메모리 사용: 맴버 클래스가 외부 클래스의 인스턴스 참조를 포함함으로써 메모리 사용량에 미치는 영향을 고려합니다.

10. 결론

  • *맴버 클래스(Member Class)는 자바에서 외부 클래스와 논리적으로 관련된 클래스를 정의할 때 유용한 도구입니다. 맴버 클래스를 static으로 선언할지, non-static**으로 선언할지는 클래스의 설계 목적과 사용 용도에 따라 달라집니다. 다음은 주요 요약입니다:
  1. 맴버 클래스의 종류:
    • 정적 맴버 클래스(Static Nested Class): 외부 클래스의 static 멤버와 독립적으로 존재하며, 외부 클래스의 인스턴스 참조를 포함하지 않습니다.
    • 비정적 맴버 클래스(Inner Class): 외부 클래스의 인스턴스와 밀접하게 연관되며, 외부 클래스의 모든 멤버에 접근할 수 있습니다.
  2. 맴버 클래스를 static으로 만들어야 하는 이유:
    • 메모리 효율성 향상
    • 캡슐화 강화
    • 코드의 명확성 및 가독성 향상
    • 유연한 상속 및 다형성 지원
  3. 맴버 클래스를 static으로 만들지 않아야 하는 경우:
    • 외부 클래스의 인스턴스 멤버에 접근이 필요할 때
    • 외부 클래스의 인스턴스와 밀접한 관련이 있을 때
    • 외부 클래스의 인스턴스 데이터를 필요로 할 때
  4. 설계 시 고려사항:
    • 클래스의 책임과 역할
    • 캡슐화와 정보 은닉
    • 유지보수성과 확장성
    • 상속과 다형성
    • 성능 고려

결론적으로, 맴버 클래스를 static으로 선언하는 것은 메모리 효율성과 캡슐화를 강화하며, 코드의 명확성과 유지보수성을 향상시키는 데 도움이 됩니다. 그러나 맴버 클래스가 외부 클래스의 인스턴스 멤버에 접근하거나, 외부 클래스의 인스턴스와 밀접하게 연관되어야 한다면, non-static 맴버 클래스로 선언하는 것이 적절합니다. 따라서, 맴버 클래스를 설계할 때는 해당 클래스가 외부 클래스와 어떻게 상호작용하는지를 신중히 고려하여 static 여부를 결정하는 것이 중요합니다.


추가 참고 자료

  • Effective Java by Joshua Bloch: 자바의 베스트 프랙티스를 다루며, 클래스 설계와 관련된 유용한 조언을 제공합니다.
  • Design Patterns: Elements of Reusable Object-Oriented Software by Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides: 객체지향 디자인 패턴에 대한 고전적인 참고서입니다.
  • Oracle Java Documentation: Nested Classes

이러한 자료들을 통해 맴버 클래스의 설계와 활용에 대한 깊이 있는 이해를 더욱 확장할 수 있습니다.

0개의 댓글