Java/EffectiveJava

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

Flambee 2025. 1. 23. 01:16

https://www.infoworld.com/article/2255920/avoid-memory-leaks-in-inner-classes.html

중첩 클래스(nested class)?

  • 다른 클래스 안에 정의된 클래스를 말한다.
  • 자신을 감싼 바깥 클래스에서만 쓰여야 하며, 그 외의 쓰임새가 있다면 톱레벨 클래스로 만들어야 한다.
public class EnclosingClass { // 바깥 클래스
    public class EnclosedClass // 중첩 클래스
}

중첩 클래스의 종류

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

정적 멤버 클래스?

  • 클래스에 static을 붙인다.
  • 다른 클래스 안에 선언되고, 바깥 클래스의 private 멤버에도 접근할 수 있다는 점만 제외하고 일반 클래스와 같다.
  • 흔히 바깥 클래스와 함께 쓰일 때만 유용한 public 도우미 클래스로 쓰인다.

(비정적)멤버 클래스?

  • 어댑터를 정의할 때 자주 쓰인다. 다른 클래스의 인스턴스처럼 보이게 하는 뷰로 사용한다.
  • 멤버 클래스의 인스턴스는 바깥 클래스의 인스턴스와 암묵적으로 연결된다.
  • 멤버 클래스에서 바깥 인스턴스(this)에 접근할 일이 없다면 무조건 static을 붙여서 정적 멤버 클래스로 만들자.
    • static을 생략했을 경우 바깥 인스턴스로의 숨은 외부 참조를 갖게되어 가비지 컬렉션이 바깥 클래스의 인스턴스를 수거하지 못해 메모리 누수가 생길 수 있다.
InnerOuter outer = new InnerOuter(); 
InnerOuter.Inner inner = outer.new Inner();

익명 클래스?

  • 익명 클래스는 바깥 클래스의 멤버가 아니다. 멤버와 달리 쓰이는 시점에 선언과 동시에 인스턴스가 만들어진다.
  • 람다를 지원하기 전에는 즉석에서 작은 함수 객체나 처리 객체를 만드는 데 익명 클래스를 주로 사용했다.
  • 정적 팩터리 메서드를 구현할 때 사용된다.(item20. 20-1 intArrayAsList 참고)

지역 클래스?

  • 지역변수를 선언할 수 있는 곳이면 실질적으로 어디서든 선언할 수 있고, 유효 범위도 지역변수와 같다.
  • 멤버 클래스처럼 이름이 있고 반복해서 사용할 수 있다.
  • 익명클래스처럼 비정적 문맥에서 사용될 때만 바깥 이느턴스를 참조할 수 있다.
  • 정적멤버는 가질 수 없으며, 가독성을 위해 짧게 작성해야 한다.
var thread = new Thread(( -> {
    ...
}))

정리

  • 메서드 밖에서도 사용해야하거나 메서드 안에 정의하기엔 너무 길다면 멤버 클래스로 만든다.
  • 멤버 클래스의 인스턴스 각각이 바깥 인스턴스를 참조한다면 비정적으로, 그렇지 않으면 정적으로 만들자.
  • 중첩 클래스가 한 메서드 안에서만 쓰이면서 그 인스턴스를 생성하는 지점이 단 한곳이고 해당 타입으로 쓰기에 적합한 클래스나 인터페이스가 이미 있다면 익명 클래스로 만들고, 그렇지 않으면 지역 클래스로 만들자