[250816] _ 중첩 클래스

호두·2025년 9월 16일

✔️ Java / Spring

목록 보기
23/25

📌 중첩 클래스

클래스안의 클래스를 말한다. 외부 클래스의 인스턴스에 연결되어 존재하는 내부 클래스, 외부 클래스의 내부에 위치 할 뿐 인스턴스에 연결되어있지 않고 독립적인 정적 중첩 클래스 라고 한다.
(핵심은 외부 인스턴스와의 관계이다.)

우리가 외부 클래스를 호출해서 사용할 때, 하나의 클래스에서만 사용을 하는 클래스가 생길 수 있다. 독립된 클래스를 사용하면 코드가 더 길어질 뿐 아니라 외부에 노출할 필요가 없는 정보를 노출하게된다.

중첩 클래스는 이런 불편함을 직관적으로 정리할 수 있다.

1. 정적 중첩 클래스 (static)

먼저 static 을 확실하게 짚고 넘어가자.

✅ static

: 클래스에 속하며 클래스가 로딩 될 때 단 한번만 메서드 영역에 생성된다. 자바가 인스턴스로 호출 가능하게 문법적 허용을 해주지만, 내부에서는 클래스 이름으로 변환해서 호출한다. (인스턴스에 속성처럼 하나하나 생성되는 게 아니다.)

⭐️ 정적 중첩 클래스는 외부 클래스의 인스턴스와는 전혀 연결되지 않는다. 따라서 외부 클래스 객체 없이도 독립적으로 생성할 수 있다. 다만 “외부 클래스와 밀접한 관련이 있다”는 점을 코드 구조상 드러내기 위해 내부에 두는 경우가 많다.

package nested.nested.ex2;

public class Network {

    public void sendMessage(String text) {
        NetworkMessage networkMessage = new NetworkMessage(text); 
        networkMessage.print();
        // ➡️ 바깥 클래스에서 정적 중첩 클래스의 객체를 생성해 메서드를 호출
    }

    private static class NetworkMessage { // 📌 정적 중첩 클래스
        private String content;

        public NetworkMessage(String content) {
            this.content = content;
        }

        public void print() {
            System.out.println(content);
        }
    }
}

➡️ 독립된 클래스를 사용하는 방식과 같다. 단지 안에 클래스가 위치할 뿐이다.

package nested.nested.ex2;

public class NetworkMain {

    public static void main(String[] args) {

        Network network = new Network();
        network.sendMessage("hello java");
    }
}

➡️ 바깥 클래스의 메서드를 통해서 정적 중첩 클래스의 객체를 생성한다.


2. 내부 클래스 (non-static)

내부 클래스는 바깥 클래스의 속성이 된다. ➡️ 필드 & 메서드
따라서 외부 클래스가 생성될 때 내부 클래스 인스턴스를 같이 만들 수도 있고, 필요할 때 new를 통해 추가로 만들 수도 있다.

내부 클래스는 외부 클래스의 private 필드/메서드에 접근할 수 있지만, 외부 클래스는 내부 클래스의 private 멤버에 직접 접근할 수 없다‼️

package nested.nested.inner.ex2;

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 { // Car 에서만 사용하는 클래스

        public void start() { // ‼️ 외부 클래스는 내부 클래스의 private 멤버에 접근 할 수 없다.
            System.out.println("충전 레벨 확인 : " + chargeLevel);
            System.out.println(model+" 의 엔진을 구동합니다.");
        }
    }
}

➡️ 필드에 내부 클래스 타입이 선언됐다. 바깥 클래스 생성자 안에 new 내부 클래스() 로 객체를 생성해서 본인의 필드에 넣었다.

🗣️ : 바깥 클래스가 내부 클래스의 참조값을 알고 있다. 하지만 private 에 접근할 수 없다. 내부 클래스는 외부 클래스의 private 에 접근 가능한데. 왜 그럴까?

우선, 일반적으로도 다른 클래스라면 참조값을 가지고 있더라도 private에는 접근 할 수 없다. 그래서 내부 클래스가 바깥 클래스의 private 필드에 접근할 수 있는 이유는 “참조값이 있어서”가 아니다.
👉 자바 언어 차원에서 컴파일러가 내부 클래스를 바깥 클래스의 멤버로 취급해 접근할 수 있게 특별히 허용하기 때문

package nested.nested.inner.ex2;

public class CarMain {
    public static void main(String[] args) {

        Car car = new Car("Model Y", 100);
        car.start();
    }
}

➡️ main에서 외부 클래스를 생성해 메서드를 실행했다. 외부클래스에서 내부클래스를 생성해서 메인에서 호출한 메서드를 실행하는데 사용한다.


❗️내부 클래스 생성 규칙

  1. 외부 클래스 내부에서 만들 때
    new 내부클래스() : 이미 외부 클래스 안이니까 어느 외부 객체에 속하는지 자동으로 알 수 있다.

  2. 외부 클래스 외부 (main 등)
    외부클래스.내부클래스 변수 = 외부인스턴스.new 내부클래스() : 내부 클래스는 외부 인스턴스에 속해 있으므로, 어느 외부 객체의 내부 클래스인지 알려줘야한다. 그래서 외부 인스턴스를 앞에 꼭 붙여야 한다.

  3. 정적 중첩 클래스
    new 외부클래스.정적중첩클래스() : 외부 객체랑 관계가 없으니까 바로 위치(소속) 만 알려주면 된다.


같은 이름의 바깥 변수 접근

package nested;

public class ShadowingMain {

    private int value = 1;

    class Inner {
        public int value = 2;

        void go() {
            int value = 3;
            System.out.println("value = " + value);
            System.out.println("this.value = " + this.value);
            System.out.println("ShadowingMain.value = "+ShadowingMain.this.value);
        }
    }

    public static void main(String[] args) {
        ShadowingMain main = new ShadowingMain();
        Inner inner = main.new Inner();
        inner.go();
    }

}

value 값이 총 3개가 있다.
자바는 항상 본인과 가장 가까운 지역변수를 먼저 확인한다. 그리고 본인이 속한 인스턴스의 멤버변수, 마지막은 외부 클래스의 본인 멤버변수로 인식한다.

하나의 value 값을 찾으면 그 값이 아닌 같은 이름을 가진 변수들은 가려진다. 이걸 섀도잉이라고 한다.

0개의 댓글