JAVA (12) - 내부 클래스
1. 개요
내부 클래스(Inner Class)는 클래스 내부에 선언된 또 다른 클래스를 의미한다. 두 클래스가 서로 긴밀한 관계에 있을 때 내부 클래스로 선언하면, 외부 클래스의 멤버들에 쉽게 접근할 수 있고 코드의 캡슐화를 높일 수 있다. 내부 클래스는 선언되는 위치와 성격에 따라 인스턴스 내부 클래스, 정적(static) 내부 클래스, 지역(local) 내부 클래스, 익명(anonymous) 내부 클래스로 나뉜다.
2. 내부 클래스의 장점과 구조
클래스 내부에 다른 클래스를 정의하는 주된 이유는 다음과 같다.
- 외부 클래스 멤버 접근 용이: 내부 클래스는 외부 클래스의
private멤버를 포함한 모든 멤버에 제약 없이 접근할 수 있다. - 캡슐화 증대: 서로 연관성이 높은 클래스를 묶어 외부로의 노출을 숨김으로써 코드의 복잡성을 줄인다.
- 가독성과 유지보수성 향상: 특정 외부 클래스에서만 사용되는 클래스를 내부에 작성하여 코드 결합도를 명확히 표현한다.
1
2
3
4
5
6
7
8
9
10
class Outer { // 외부 클래스
private int outerValue = 10;
class Inner { // 인스턴스 내부 클래스
void printValue() {
System.out.println(outerValue); // 외부 클래스의 private 변수에 직접 접근 가능
}
}
}
3. 내부 클래스의 종류
내부 클래스는 변수가 선언되는 위치에 따라 구분되는 방식과 유사하게 분류된다.
(1) 인스턴스 내부 클래스 (Instance Inner Class)
외부 클래스의 멤버변수 선언 위치에 선언하며, 외부 클래스의 인스턴스가 먼저 생성되어야 사용할 수 있다.
- 외부 클래스의 인스턴스 멤버와 static 멤버 모두에 접근할 수 있다.
- 외부 클래스 인스턴스와의 숨은 참조를 유지하므로 메모리 누수(Memory Leak)에 주의해야 한다.
1
2
3
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner(); // 외부 인스턴스를 통해 생성
(2) 정적 내부 클래스 (Static Nested Class)
내부 클래스에 static 키워드가 붙은 형태다. 외부 클래스의 인스턴스를 생성하지 않고도 단독으로 객체 생성이 가능하다.
- 외부 클래스의
static멤버만 접근할 수 있으며, 인스턴스 멤버에는 직접 접근할 수 없다. - 외부 클래스 인스턴스에 대한 참조를 가지지 않으므로 메모리 관리에 효율적이다. 외부 클래스와 독립적으로 작동해야 하는 내부 클래스에 권장된다.
1
2
3
4
5
6
7
8
9
10
11
class Outer {
static class StaticInner {
void msg() {
System.out.println("Static Inner Class Call");
}
}
}
// 외부 클래스 인스턴스 생성 없이 직접 생성
Outer.StaticInner inner = new Outer.StaticInner();
(3) 지역 내부 클래스 (Local Inner Class)
외부 클래스의 메서드 내부나 초기화 블록 내에 선언되어 사용되는 클래스다.
- 메서드가 실행될 때만 유효하며, 메서드 호출이 끝나면 사용이 불가능하다.
- 메서드 내의 지역 변수를 사용할 때, 해당 지역 변수는
final이거나 상수에 준하는 상태(effectively final)여야 한다.
(4) 익명 내부 클래스 (Anonymous Inner Class)
이름이 없는 클래스로, 클래스의 선언과 객체의 생성을 동시에 진행하는 형태다.
- 단 한 번만 사용되는 일회성 객체를 생성할 때 주로 활용된다.
- 이벤트 처리기나 람다식(Lambda)의 기초 구조로 많이 쓰인다.
1
2
3
4
5
6
7
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("Anonymous Inner Class");
}
};
4. 정적(static) 내부 클래스 사용의 중요성
내부 클래스를 작성할 때 특별히 외부 클래스의 인스턴스 변수를 참조할 이유가 없다면, static 내부 클래스로 선언하는 것이 바람직하다.
비정적(non-static) 내부 클래스는 자신을 감싸고 있는 외부 클래스 인스턴스에 대한 숨은 참조(outer reference)를 저장한다. 이로 인해 내부 클래스 객체가 살아 있는 동안 외부 클래스 객체도 GC(Garbage Collector)에 의해 수거되지 못하는 메모리 누수가 발생할 위험이 있다. 독립적인 유틸리티 클래스나 데이터 전달용 DTO 구조 등에서는 static 내부 클래스를 사용하는 것이 안전하다.
5. 정리
내부 클래스는 코드의 논리적 그룹화와 캡슐화를 실현하는 강력한 도구다. 클래스 간의 관계가 밀접할 때 코드 구조를 더욱 깔끔하게 유지해 준다. 단, 인스턴스 내부 클래스는 외부 클래스와의 숨은 참조로 인해 메모리 누수를 유발할 수 있으므로, 외부 인스턴스를 참조할 필요가 없다면 정적(static) 내부 클래스로 정의하는 것이 좋다.