Java Nested - 내부 클래스

이전 정적 중첩 클래스와 바깥클래스와의 관계가 없었다.
이번 내부 클래스에서는 바깥클래스의 인스턴스 요소가 되어 소속된다.

정적 중첩 클래스

  • static 키워드로 생성
  • 바깥클래스의 인스턴스로 소속되지 않음

내부 클래스

  • static 키워드 없이 생성
  • 바깥 클래스의 인스턴스로 소속

예제코드

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);

            // 외부 클래스의 인스턴스 멤버로 접근 가능, private 또한 접근 가능
            System.out.println(outInstanceValue);

            // 외부 클래스의 클래스 멤버로 접근 가능, private 또한 접근 가능
            // 정적 변수
            System.out.println(outClassValue);
        }
    }
}
  • 내부 클래스는 static 없음
  • 내부 클래스
    • 자신의 멤버는 접근 가능
    • 바깥클래스의 인스턴스 멤버 접근 가능
    • 바깥클래스의 클래스 멤버 접근 가능

private 접근제어자

  • private 접근제어자는 같은 클래스 안에서만 접근 가능
  • 내부 클래스 또한 바깥 클래스 안에 있다. 즉, 내부 클래스는 바깥클래스의 private 접근제어자를 자유롭게 접근 가능하다.

내부 클래스 인스턴스 생성

외부에서 InnerOuter 내부클래스를 호출하는 예제코드를 바라보자.

Main.class

public class Main {
    public static void main(String[] args) throws Exception {
        InnerOuter outer = new InnerOuter();
        InnerOuter.Inner inner = outer.new Inner();
    }
}

내부 클래스 인스턴스 생성 문법이 특이한 것을 볼 수 있다.
먼저, 바깥클래스의 인스턴스 참조가 필요함으로 먼저 생성한다. (new InnerOuter())
인스턴스 내부 참조점(.)을 통해 새로운 내부 클래스 소속과 인스턴스를 새로 생성하였다.(outer.new Inner())

코드의 Inner()는 InnerOuter()의 인스턴스 참조를 갖고 있다.
이 생성의 핵심은 인스턴스의 인스턴스 생성으로 이루어진 점이다.

inner.print();
System.out.println(inner.getClass());

1
2
3
class InnerOuter$Inner

중첩,내부 클래스는 $달러로 표시된다.

생성이 안되는 케이스

다음과 같이 선언하여 사용할 수 없다.
내부 클래스 생성에는 바깥클래스의 인스턴스가 반드시 필요하다.

new InnerOuter().Inner();

java: cannot find symbol

// InnerOuter outer = new InnerOuter();
InnerOuter.Inner inner = outer.new Inner();

java: cannot find symbol


참고

내부 클래스 생성에는 바깥 클래스 인스턴스 안에 생성한다고 하였으나 개념으로만 그렇다.

실제에는 바깥 클래스와 내부 클래스 각각 독립적으로 생성한 모습이고 내부 클래스는 바깥클래스의 참조 보관하는 그림이다.