요약
클래스 내부에 클래스를 만드는 방법은 정적 멤버 클래스, 비정적 멤버 클래스, 익명 클래스, 지역 클래스가 있다.
상황에 맞춰서 가장 적절한 중첩 클래스를 사용하도록 하자. 멤버 클래스에서 바깥 인스턴스에 접근할 일이 없다면 무조건 static을 붙여서 정적 멤버 클래스로 만들어서 사용하자.
메서드 밖에서도 사용해야 하거나 메서드 안에 정의하기엔 너무 길고, 바깥 클래스를 참조한다 → 비정적 멤버 클래스
메서드 밖에서도 사용해야 하거나 메서드 안에 정의하기엔 너무 길고 바깥 클래스를 참조하지 않음 → 정적 멤버 클래스
중첩 클래스가 한 메서드 안에서만 쓰이면서 그 인스턴스를 생성하는 지점이 단 한곳이고, 해당 타입으로 쓰기에 적합한 클래스나 인터페이스가 이미 있다 → 익명 클래스로 만들자.
아니면 지역 클래스로 만들자.
중첩 클래스란?
다른 클래스 안에 정의된 클래스이고, 자신을 감싼 바깥 클래스에서만 사용되어야 한다.
종류로는 정적 멤버 클래스, (비정적) 멤버 클래스, 익명 클래스, 지역 클래스가 있다.
정적 멤버 클래스를 제외한 모든 중첩 클래스는 내부 클래스(inner class)이다.
- 중첩 클래스를 왜 쓰는가?
- 클래스 간 논리적 그룹을 나타낼 때 사용한다.
- model 객체에서 상위 모델과 하위 모델이 있을 때 static nested class 사용
- 향상된 캡슐화
- 좋은 가독성과 유지보수성
- 클래스 간 논리적 그룹을 나타낼 때 사용한다.
1. 정적 멤버 클래스
클래스 내부에 있는 static 클래스이다.
// 모양새
class Outer {
변수;
메소드;
private 멤버;
public static class Inner {
}
}
// 객체 생성
Outer.Inner 객체 = new Outer.Inner();
- 특징
- 다른 클래스 내부에서 선언된다
- 바깥 클래스의 private 멤버에도 접근할 수 있다
- 정적 멤버와 같은 접근 규칙을 적용받는다 (ex. private 선언시 바깥 클래스에서만 접근 가능)
- private 정적 멤버 클래스
- 바깥 클래스가 표현하는 객체의 한 부분(구성 요소)을 나타낼 때 주로 사용한다.
- Map 인터페이스 구현체는 엔트리 객체를 private static 멤버 클래스로 만든다?
→ 바깥 클래스 인스턴스와 독립적으로 존재해야하는 경우 사용해야 한다.
2. 비정적 멤버 클래스
클래스 내부에 있는 non-static 중첩 클래스이다.
비정적 멤버 클래스는 바깥 인스턴스 없이는 생성할 수 없다.
비정적 멤버 클래스의 인스턴스는 바깥 클래스의 인스턴스와 암묵적으로 연결된다(숨은 외부참조).
즉, 비정적 멤버 클래스의 인스턴스 메서드에서 정규화된 this(**바깥 *클래스명.this*** 형태)로 바깥 인스턴스 메서드 호출 하거나 바깥 인스턴스의 참조를 가져올 수 있다.
// 모양새
class Outer {
변수;
메소드;
this.~~~
메서드1 {
new Inner(); // 내부 클래스 생성자 호출
}
public class Inner {
이너 메서드 {
Outer.this.메서드1
}
}
}
- 바깥 인스턴스와 비정적 멤버 인스턴스 관계 형성 방법
- 자동
- 바깥 클래스 메서드 안에 비정적 멤버 클래스 생성자가 호출되고 멤버 클래스 인스턴스 생성 시 자동으로 관계 형성
- 수동
- 바깥 인스턴스 [클래스.new](<http://클래스.new>) Member Class(args) 호출로 수동 생성도 가능
- 자동
- 숨은 외부 참조 특징
- 한 번 형성된 관계는 변경 불가능하다
- 관계 정보는 비정적 멤버 클래스 인스턴스 안에 만들어진다
- 메모리 공간 차지
- 생성 시간 더 걸림
- GC에서 멤버 클래스 인식이 안돼 메모리 누수 발생 가능
- 참조가 눈에 보이지 않아 문제 원인을 찾기 어려워짐
- 사용 예시 - 어댑터(Adapter)
- 어떤 클래스의 인스턴스를 감싸 마치 다른 클래스의 인스턴스처럼 보이게 하는 뷰를 사용할 때
→ 멤버 클래스에서 바깥 인스턴스에 접근할 일이 없다면 무조건 static을 붙여서 정적 멤버 클래스로 만들자.
3. 익명 클래스
이름이 없는 클래스를 의미한다.
- 장점
- 사용되는 시점에 선언과 동시에 인스턴스 생성
- 코드 어디에서든 만들 수 있다
- 비정적 익명 클래스
- 바깥 클래스 인스턴스 참조 가능
- 정적 익명 클래스
- 상수표현을 위해 초기화된 final 기본 타입과 문자열 필드만 가질 수 있다
- 단점
- 선언한 지점에서만 인스턴스 생성 가능
- instanceof 검사나 클래스 이름이 필요한 작업 수행 불가능
- 인터페이스 구현 및 상속 불가능
- 코드가 길어질 경우 가독성 저하
→ 람다 출시 이후에는 람다가 익명 클래스를 거의 대체할 수 있다.
4. 지역 클래스
지역 변수를 선언할 수 있는 곳에 어디든 만들 수 있는 클래스를 의미한다. 유효 범위도 지역변수와 같다. 메서드 내부에서 new로 생성한 다음에 메서드 내부에서만 사용이 가능하다.
class Outer {
변수;
메소드1;
메소드2() {
지역변수;
class Inner {
}
}
}
- 특징
- 이름이 있고, 반복해서 사용 가능
- 비정적 문맥에서 사용될 때만 바깥 인스턴스 참조 가능
- 정적 멤버 가질 수 없다
- 가독성을 위해 짧게 작성해야 한다
'Dev Language > EffectiveJava' 카테고리의 다른 글
[EffectiveJava] 이왕이면 제네릭 메서드로 만들라 (0) | 2025.01.11 |
---|---|
[EffectiveJava]이왕이면 제네릭 타입으로 만들라 (0) | 2025.01.05 |
[EffectiveJava] 로 타입(raw type)은 사용하지 말라 (4) | 2024.12.29 |
[EffectiveJava] 인터페이스는 구현하는 쪽을 생각해 설계하라 (1) | 2024.12.08 |
[Effective Java] 생성자 대신 정적 팩터리 메서드를 고려하라 (0) | 2023.11.09 |