1. 내부 클래스
- 자바에서는 클래스 안에 또 다른 클래스를 선언할 수 있다.
이러한 클래스들을 중첩 클래스(Nested Class) 라고 부른다. - 그 중에서도 static 키워드 없이 선언된 클래스는 내부 클래스(Inner Class) 라고 부른다.
- 내부 클래스는 바깥 클래스의 인스턴스에 소속되며, 바깥 클래스의 모든 멤버(필드, 메서드) 에 접근 가능하다.
2. 내부 클래스 사용 이유
- 캡슐화
- 외부에서 사용할 필요가 없는 클래스는 감춰야한다.
- 클래스 설계의 기본 원칙 중 하나는 정보 은닉(information hiding) 이다.
즉, 외부에서 직접 접근할 필요가 없는 구현 세부사항은 가능한 한 감춰야 한다. - 내부 클래스는 외부에 공개되지 않고, 바깥 클래스 내부에서만 쓰이도록 설계할 수 있기 때문에
불필요한 클래스를 외부에 노출하지 않아도 된다.
- 논리적 그룹화
- 특정 기능에서만 사용하는 클래스를 그 안에 정의하면 코드 가독성이 올라간다.
- 기능적으로 밀접한 관계인 클래스는 함께 묶는 것이 유지보수에 더 유리하다.
- 내부 클래스는 특정 기능에서만 사용되는 클래스가 있을 때, 해당 기능 내부에 선언함으로써 관련 로직을 논리적으로 묶을 수 있다.
3. 예제 InnerClass
public class InnerOuter {
private static int outClassValue = 3;
private int outInstanceValue = 2;
class Inner {
private int innerInstanceValue = 1;
public void print() {
System.out.println(innerInstanceValue); // 1
System.out.println(outInstanceValue); // 2
System.out.println(outClassValue); // 3
}
}
}
public class InnerOuterMain {
public static void main(String[] args) {
InnerOuter outer = new InnerOuter();
InnerOuter.Inner inner = outer.new Inner();
inner.print();
}
}
- 내부 클래스는 바깥 클래스 인스턴스.내부 클래스 생성() 방식으로 생성해야 한다.
- 바깥 클래스의 모든 멤버(static, non-static)에 접근 가능하다.
- 내부 클래스는 바깥 클래스 인스턴스에 소속되어 동작한다.
4. 내부 클래스 활용
리펙토링 전
public class Engine {
private Car car;
public Engine(Car car) {
this.car = car;
}
public void start() {
System.out.println(car.getChargeLevel());
System.out.println(car.getModel() + "의 엔진을 구동합니다.");
}
}
public class Car {
private String model;
private int chargeLevel;
private Engine engine;
public Car(String model, int chargeLevel) {
this.model = model;
this.chargeLevel = chargeLevel;
this.engine = new Engine(this);
}
public String getModel() { return model; }
public int getChargeLevel() { return chargeLevel; }
public void start() {
engine.start();
System.out.println(model + " 시작 완료");
}
}
- Engine은 Car에서만 사용하는데도 외부 클래스처럼 보임
- getModel(), getChargeLevel() 같은 메서드를 외부에 공개해야 함 → 캡슐화 깨짐
리펙토링
public class Car {
private String model;
private int chargeLevel;
private Engine engine;
public Car(String model, int chargeLevel) {
this.model = model;
this.chargeLevel = chargeLevel;
this.engine = new Engine();
}
public void start() {
engine.start();
System.out.println(model + " 시작 완료");
}
private class Engine {
public void start() {
System.out.println("충전 레벨 확인: " + chargeLevel);
System.out.println(model + "의 엔진을 구동합니다.");
}
}
}
- Engine은 더 이상 외부에 노출되지 않음
- Car 내부 정보에 직접 접근 가능 → getter 없이도 협력 가능
- 코드 응집도 상승, 외부 노출 최소화
| 구분 | 정적 중첩 클래스 | 내부 클래스 |
| static | O | X |
| 바깥 인스턴스 필요 | X | O |
| 바깥 멤버 접근 | static만 | 전부 가능 |
| 생성 방법 | new Outer.Nested() | outer.new Inner() |
| 목적 | 논리적 분리 | 논리적 + 구조적 소속 |
'Java' 카테고리의 다른 글
| Java 중급 1 - 중첩클래스, 내부 클래스(4) (0) | 2025.04.21 |
|---|---|
| Java 중급 1 - 중첩클래스, 내부 클래스(3) (0) | 2025.04.16 |
| Java 중급 1 - 중첩클래스, 내부 클래스(1) (0) | 2025.04.12 |
| Java 중급 1 - 날짜와 시간(3) (0) | 2025.03.23 |
| Java 중급 1 - 날짜와 시간(2) (0) | 2025.03.19 |