티스토리 뷰

728x90
반응형

멤버 클래스는 되도록 static으로 만들라.


  • 중첩 클래스란 다른 클래스 내부에 정의된 클래스를 말합니다. 중첩 클래스는 자신을 감싼 바깥 클래스에서만 쓰여야하며, 그 외에 쓰임새가 있다면 톱 레벨 클래스로 만들어야 합니다.(static)

 

💡 중첩 클래스의 종류

  • 정적 멤버 클래스
  • 비정적 멤버 클래스
  • 익명 클래스
  • 지역 클래스

 

정적 멤버 클래스


💡 특징

  • 다른 클래스 안에 선언되는 클래스입니다.
  • 바깥 클래스의 private 멤버에도 접근할 수 있습니다.
  • 정적 멤버 클래스는 다른 정적 멤버와 똑같은 접근 규칙을 적용받습니다.

 

정적 멤버 클래스와 비정적 멤버 클래스의 차이


  • 정적 멤버 클래스와 비정적 멤버 클래스의 구문상 차이는 static이 있냐 없냐의 차이지만 의미상의 차이는 생각보다 큽니다.
  • 비정적 멤버 클래스는 바깥 클래스의 인스턴스와 암묵적으로 연결됩니다. 그래서 비정적 멤버 클래스의 인스턴스 메서드에서 정규화된 this를 사용해 바깥 인스턴스의 메서드를 호출하거나 바깥 인스턴스의 참조를 가져올 수 있습니다.
  • 정규화된 this란, 클래스명.this 형태로 바깥 클래스의 이름을 명시하는 용법을 말합니다.
  • 따라서 개념상 중첩 클래스의 인스턴스가 바깥 인스턴스와 독립적으로 존재할 수 있다면 정적 멤버 클래스로 만들어야 합니다. 비정적 멤버 클래스는 바깥 인스턴스 없이는 존재할 수 없기 때문입니다.

💡 선언 방법

public class OuterClass {

    private String name;

    // 정적 멤버 클래스
    public static class StaticInnerClass {

        private int age;
    }
    
    // 비정적 멤버 클래스
    public class InnerClass {
        
        private int age;
    }
}

 

💡 생성

import static com.effectivejava.study.chapter03.Item24.OuterClass.StaticInnerClass;

public class EffectiveJavaApplication {

    public static void main(String[] args) throws Exception {

        // 정적 멤버 클래스 생성
        OuterClass.StaticInnerClass staticInnerClass = new StaticInnerClass();

        // 비정적 멤버 클래스 생성
        OuterClass outerClass = new OuterClass();
        OuterClass.InnerClass innerClass = outerClass.new InnerClass();
    }
}

 

💡 메모리 누수 가능성

  • 비정적 멤버 클래스의 경우 바깥 클래스에 대한 참조를 가지고 있기 때문에 메모리 누수가 발생할 여지가 있습니다. 바깥 클래스는 더 이상 사용되지 않지만 내부 클래스의 참조로 인해 GC가 수거하지 못해서 바깥 클래스 메모리 해제를 하지 못하는 경우가 발생할 수 있습니다. 

 

비정적 멤버 클래스


💡 특징

  • 바깥 클래스의 인스턴스 없이는 생성할 수 없습니다.
  • 멤버 클래스가 인스턴스화될 때 비정적 멤버 클래스와 바깥 클래스의 인스턴스 사이의 관계가 확립되며 변경할 수 없습니다.
  • 정규화된 this를 이용해 바깥 클래스의 인스턴스 참조를 가져올 수 있습니다.

💡 문제점

  • 바깥 인스턴스로의 숨은 외부 참조를 가지게 되며 이 참조를 저장하기 위해 시간과 공간이 소비됩니다.
  • GC가 바깥 클래스의 인스턴스를 수거하지 못하는 메모리 누수가 발생할 수 있습니다.
  • 참조가 눈에 보이지 않으므로 문제의 원인을 찾기가 힘듭니다.
  • 즉 멤버 클래스에서 바깥 인스턴스에 접근해야 하는 경우가 명확히 없다면 static을 붙혀 정적 멤버 클래스로 만드는 것이 좋습니다.

 

익명 클래스


💡 특징

  • 익명이므로 이름이 없습니다.
  • 바깥 클래스의 멤버도 아닙니다.
  • 쓰이는 시점에서 선언과 동시에 인스턴스가 만들어집니다.
  • 비정적인 문맥에서 사용될 때만 바깥 클래스의 인스턴스를 참조할 수 있습니다.
  • 상수 표현을 위해 초기화된 final 기본 타입과 문자열 필드만 가질 수 있습니다.

 

💡 제약

  • 선언한 지점에서만 인스턴스 생성이 가능합니다.
  • instanceof 검사나 클래스의 이름이 필요한 작업에는 수행이 불가능합니다.
  • 여러 인터페이스 구현이나 인터페이스를 구현하는 동시에 다른 클래스 상속도 불가능합니다.
  • 익명 클래스를 사용하는 클라이언트는 익명 클래스가 상위 타입에서 상속한 멤버외에는 호출할 수 없습니다.
  • 표현식 중간에 등장하기 때문에 코드가 길수록 가독성이 떨어집니다.

 

지역 클래스


💡 특징

  • 가장 드물게 사용하는 중첩 클래스입니다.
  • 지역 변수를 선언할 수 있는 곳이라면 어디든 선언할 수 있습니다.
  • 유효범위도 지역변수와 동일합니다.
  • 이름이 있고 반복해서 사용할 수 있습니다.
  • 비정적 문맥에서 사용될 때만 바깥 인스턴스를 사용할 수 있습니다.
  • 정적 멤버는 가질 수 없고 가독성을 위해 짧게 선언해야 합니다.

 

 

참고 자료)

https://tecoble.techcourse.co.kr/post/2020-11-05-nested-class/

 

 

 

 

 

728x90
반응형