[Effective Java] 아이템 24 : 멤버 클래스는 되도록 static으로 만들라

HyeBin, Park·2022년 6월 29일
0

Effective Java Study

목록 보기
19/20
post-thumbnail

아이템 24 - 멤버 클래스는 되도록 static으로 만들라

중첩 클래스

  • 클래스 안에 정의 되어 있는 클래스
  • 자신을 감싼 바깥 클래스에서만 쓰여야 하며, 그외의 쓰임새가 있다면 톱레벨 클래스로 만들어야한다.
  • 중첩클래스를 포함하는 외부 클래스를 Outer 클래스, 내부에 포함된 클래스를 중첩클래스 또는 Inner 클래스

중첩 클래스의 종류

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

중첩 클래스 : 정적 멤버 클래스

  • 다른 클래스 안에 선언되고, 바깥 클래스의 private   멤버에도 접근할 수 있다는 점만 제외하고 일반 클래스와 똑같다.
  • 다른 정적 멤버와 똑같은 접근 규칙을 적용받는다.
    => private 로 선언하면 outer 클래스에서만 접근할 수 있다.
  • Outer 클래스와 함께 쓰일 때만 유용한 public 도우미 클래스로 쓰인다.
  • 아래의 Operation 열거 타입은 Caculator 클래스의 public 정적 멤버 클래스가 되어야 한다.
    => Calculator.Operation.PLUS , Calculator.Operation.MINUS 같은 형태
public enum Operation {
	PLUS, MINUS, TIMES, DIVIDE;
    ...
}

중첩 클래스 : 비정적 멤버 클래스

  • 정적 멤버 클래스와의 차이는 static 이 붙어 있고 없고 뿐이지만 의미상 차이는 크다.
  • 비정적 멤버 클래스의 인스턴스는 outer 클래스의 인스턴스와 암묵적으로 연결된다.
  • 인스턴스 메서드에서 정규화된 this 를 사용해 outer 인스턴스의 메서드를 호출하거나 바깥 인스턴스의 참조를 가져올 수 있다.
    • 정규화된 this?
      • className.this 형태로 outer 클래스의 이름을 명시하는 용법
  • 개념상 중첩 클래스의 인스턴스가 outer 인스턴스와 독립적으로 존재할 수 있다면 정적 멤버 클래스로 만들어야한다.

  • 비정적 멤버 클래스는 outer 인스턴스 없이는 생성할 수 없다.
  • 관계 정보는 비정적 멤버 클래스의 인스턴스 안에 만들어져 메모리 공간을 차지하며, 생성 시간도 더 걸린다.

어댑터를 정의할 때 자주 쓰이는 비정적 멤버 클래스

  • 어떤 클래스의 인스턴스를 감싸 마치 다른 클래스의 인스턴스처럼 보이게 하는 뷰로 사용하는 것
  • Map 인터페이스의 구현체들은 보통 자신의 컬렉션 뷰를 구현할 때 비정적 멤버 클래스를 사용한다.

멤버 클래스에서 outer 인스턴스에 접근할 일이 없다면 무조건 static 붙여서 정적 멤버 클래스로 만들자.

  • static을 생략하면 outer  인스턴스로 숨은 외부 참조를 갖게 된다.
  • 참조를 저장하려면 시간과 공간이 소비되고 심각한 문제는 가비지 컬렉션이 outer클래스의 인스턴스를 수거하지 못하는 메모리 누수가 생길 수 있다.

private 정적 멤버 클래스

  • 흔히 바깥 클래스가 표현하는 객체의 한 부분을 나타낼 때 쓴다.
  • Map 구현체는 각각의 키-값 쌍을 표현하는 엔트리 객체들을 가지고 있다.
  • 모든 엔트리가 맵과 연관되어 있지만 엔트리의 메서드들은 맵을 직접 사용하지는 않는다.
  • 엔트리를 비정적 멤버 클래스로 표현하느 것은 낭비고, private 정적 멤버 클래스가 가장 알맞다.

중첩클래스 : 익명 클래스

  • 익명 클래스는 outer  클래스의 멤버가 아니고 쓰이는 시점에 선언과 동시에 인스턴스가 만들어지고 코드의 어디서든 만들 수 있다.
  • 비정적인 쿤맥에서 사용될 때만 outer클래스의 인스턴스를 참조할 수 있다.
  • 정적 문맥에서라도 상수 변수 이외의 정적 멤버는 가질 수 없다.
  • 상수 표현을 위해 초기화된 final 기본 타입과 문자열 필드만 가질 수 있다.
  • 정적 팩토리 메서드를 구현할 때 쓰인다.

익명 클래스 응용

  • 선언한 지점에서만 인스턴스를 만들 수 있다.
  • instanceof 검사나 클래스의 이름이 필요한 작업은 수행할 수 없다.
  • 여러 인터페이스를 구현할 수 없고, 인터페이스를 구현하는 동시에 다른 클래스를 상속할 수도 없다.
  • 익명 클래스를 사용하는 클라이언트는 그 익명 클래스가 상위 타입에서 상속한 멤버 외에는 호출할 수 없다.
  • 표현식 중간에 등장하므로 짧지 않으면 가독성이 떨어진다. 람다를 지원하기 전에는 즉석에서 작은 함수 객체나 처리 객체를 만드는 데 익명 클래스를 주로 사용했다.

중첩 클래스 : 지역 클래스

  • 가장 드물게 사용된다.
  • 지역 변수를 선언할 수 있는 곳이면 실질적으로 어디서든 선언할 수 있고, 유효 범위도 지역변수와 같다.
  • 멤버 클래스처럼 이름이 있고 반복해서 사용할 수 있다.
  • 익명 클래스처럼 비정적 문잭에서 사용될 때만 outer 인스턴스를 참조할 수 있다.
  • 정적 멤버는 가질 수 없으며 가독성을 위해 짧게 작성해야한다.

정리하기

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

0개의 댓글