Item 24 - 멤버 클래스는 되도록 static으로 만들어라
중첩 클래스 (nested class)
- 중첩 클래스는 다른 클래스 안에 정의된 클래스를 말한다.
- 자신을 감싼 바깥 클래스에서만 쓰여야한다.
- 정적 멤버 클래스, (비정적) 멤버 클래스, 익명 클래스, 지역 클래스
정적 멤버 클래스
- 다른 클래스 내부에서 static으로 선언된 클래스
- 다른 정적 멤버와 똑같은 접근 규칙을 적용받는다.
- 흔히 바깥 클래스와 함께 쓰일 때만 유용한 public 도우미 클래스로 쓰인다.
1
2
3
4
5
public class Calculator {
public enum Operation { // 열거 타입도 암시적 static 이다.
PLUS, MINUS, MULTIPLE, SUBTRACT
}
}
비정적 멤버 클래스
- 다른 클래스 내부에서 static 없이 선언된 클래스
- 비정적 멤버 클래스의 인스턴스는 바깥 클래스의 인스턴스와 암묵적으로 연결된다.
- ‘클래스명.this’로 바깥 인스턴스의 메서드 호출, 바깥 인스턴스의 참조를 가져올 수 있다.
- 어댑터 정의 시 자주 쓰인다.
- 어떤 클래스의 인스턴스를 감싸서 마치 다른 클래스의 인스턴스처럼 보이게 하는 뷰로 사용
- 멤버 클래스에서 바깥 인스턴스를 참조할 필요가 없다면 무조건 정적 멤버 클래스로 만들자.
1
2
3
4
5
6
7
8
9
10
11
12
// 컬렉션 인터페이스 구현들이 자신의 반복자를 구현할 때 비정적 멤버 클래스 사용
public class MySet<E> extends AbstractSet<E> {
... // 생략
@Override public Iterator<E> iterator() {
return new MyIterator();
}
private class MyIterator implements Iterator<E> {
... // 생략
}
}
익명 클래스
- 바깥 클래스의 멤버가 아니며, 쓰이는 시점에 선언과 동시에 인스턴스가 만들어진다.
- 비정적인 문맥에서 사용될 때만 바깥 클래스의 인스턴스를 참조할 수 있다.
- 자바에서 람다를 지원하기 전에 즉석에서 작은 함수 객체나 처리 객체를 만들 때 사용했다.
- 자바가 람다를 지원한 이후(자바8)부터는 익명 클래스보다 람다를 주로 사용한다.
익명 클래스의 제약
- 선언한 지점에서만 인스턴스를 만들 수 있다.
- instanceof 검사나 클래스의 이름이 필요한 작업은 수행할 수 없다.
- 여러 인터페이스를 구현할 수 없고, 인터페이스를 구현함과 동시에 다른 클래스를 상속할 수도 없다.
- 익명 클래스가 상위 타입에 상속한 멤버 외에는 호출이 불가능하다.
1
2
3
4
5
6
7
8
9
10
// 익명 클래스
Collections.sort(list, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1, o2);
}
});
// 자바8 이후 람다로 변경
Collections.sort(list, (o1, o2) -> Integer.compare(o1, o2));
지역 클래스
- 네 가지 중첩 클래스 중 가장 드물게 사용된다.
- 지역 변수를 선언할 수 있는 곳이면 어디서든 선언가능하고, 유효범위도 지역변수와 같다.
- 비정적 문맥에서 사용될 때만 바깥 인스턴스를 참조할 수 있다.
- 정적 멤버는 가질 수 없으며, 가독성을 위해 짧게 작성해야 한다.
💡 핵심 정리
- 중첩 클래스는 정적 멤버 클래스, 비정적 멤버 클래스, 익명 클래스, 지역 클래스가 있다.
- 메서드 밖에서도 사용하거나 메서드 안에 정의하기엔 너무 길다면 멤버 클래스로 만든다.
- 멤버 클래스의 인스턴스가 바깥 인스턴스를 참조한다면 비정적으로, 아니라면 정적으로 만들자.
- 중첩 클래스가 한 메서드 안에서만 쓰이고 해당 타입으로 쓰기에 적절한 클래스나 인터페이스가 이미 있다면 익명 클래스로 만들고 아니면 지역 클래스로 만들자.
참고 🕶️
This post is licensed under CC BY 4.0 by the author.