[기본 개념] 2 | (8.1) 내부클래스, 익명클래스

728x90

[기본 개념] 2 | (8.1) 내부클래스, 익명클래스

1> 내부클래스란?

2> 내부클래스의 종류와 특징

3> 내부클래스의 선언

4> 내부클래스의 제어자와 접근성

5> 익명클래스(anonymous class)

1. 내부클래스란?

 내부클래스는 클래스 내에 선언된 클래스이다. 클래스 내에 선언하는 이유는 두 클래스가 서로 긴밀한 관계이기 때문이다.

 

 내부클래스를 사용하면 두 클래스의 멤버들 간에 서로 쉽게 접근할 수 있다는 장점과 외부에는 불필요한 클래스를 감춤으로 코드의 복잡성을 줄일 수 있다.

 

내부클래스의 장점

- 내부클래스에서 외부클래스의 멤버들을 쉽게 접근할 수 있다.

- 코드의 복잡성을 줄일 수 있다.

 


    class A {

        . . .
    }

    class B {
        . . .
    }

---->
    class A {    // 외부클래스
        . . .
        class B {    // 내부클래스
            . . . 
        }
        . . . 
    }

 

이때 내부클래스인 B는 다른 클래스에서 잘 사용되지 않아야 한다.

2. 내부클래스의 종류와 특징

 내부클래스는 마치 변수를 선언하는 것과 같은 위치에 선언할 수 있으며, 선언위치에 따라 다음과 같이 구분된다.

 

내부클래스 특징
인스턴스클래스
(instance class)
외부클래스의 멤버변수 선언위치에 선어하며, 외부클래스의 인스턴트멤버처럼 다뤄진다. 주로 외부클래스의 인스턴스멤버들과 관련된 작업에 사용된다.
스태틱클래스
(static class)
외부클래스의 멤버변수 선언위치에 선언하며, 외부클래스의 static멤버처럼 다뤄진다. 주로 외부클래스의 static멤버, 특히 static메서드에서 사용된다.
지역클래스
(local class)
외부클래스의 메서드나 초기화블럭 안에 선언하며, 선언된 영역 내부에서만 사용된다.
익명클래스
(anonymous class)
클래스의 선언과 객체의 생성을 동시에 하는 이름없는 클래스(일회용)

3. 내부클래스의 선언

아래의 오른쪽 코드에는 외부클래스에 3개의 서로 다른 종류의 내부클래스를 선언했다.

 

 선언된 위치에 따라 인스턴스클래스, 스태틱클래스, 지역클래스로 나뉜다. 그리고 각 내부클래스의 선언위치에 따라 같은 선언위치의 변수와 동일한 유효범위(scope)와 접근성(accessibility)을 갖는다.

 


    class Outer {

        int iv = 0 ;
        static int cv = 0 ;
   
        void myMethod( ) {
            int lv = 0 ;
        }
   }

<---->
   class Outer {

        class InstanceInner { }
        static class StaticInner { }
    
        void myMethod( ) {
            class LocalInner { }
        }
    }

4. 내부클래스의 제어자와 접근성

 내부클래스도 클래스이기 때문에 abstract나 final과 같은 제어자를 사용할 수 있고, private, protected과 접근제어자도 사용할 수 있다.

 

예제/InnerEx1.java

public class InnerEx1 {
    class InstanceInner {
        int iv = 100;
//      static int cv = 100;            // error. staic변수를 선언할 수 없다.
        final static int CONST = 100;   // final static은 상수이므로 허용
    }

    static class StaticInner {
        int iv = 200;
        static int cv = 200;            // static클래스만 static멤버를 정의할 수 있다.
    }

    void myMethod() {
        class LocalInner {
            int iv = 300;
//          static int cv = 300;            // error. static변수를 선언할 수 없다.
            final static int CONST = 300;   // final static은 상수이므로 허용
        }
    }

    public static void main(String[] args) {
        System.out.println(InstanceInner.CONST);
        System.out.println(StaticInner.cv);
    }
}
실행결과

100
200

 

 내부클래스 중에 스태틱클래스(StaticInner)만 static멤버를 가질 수 있다. 다만 final static이 동시에 붙은 변수는 상수(constant)이므로 모든 내부클래스에서 정의가 가능하다.

 

예제/InnerEx2.java

public class InnerEx2 {
    class InstanceInner { }
    static class StaticInner { }

    // 인스턴스멤버 간에는 서로 직접접근이 가능하다.
    InstanceInner iv = new InstanceInner();
    // static멤버 간에는 서로 직접접근이 가능하다.
    static StaticInner cv = new StaticInner();

    static void staticMethod() {
        // static멤버는 인스턴스멤버에 직접접근할 수 없다.
//      InstanceInner obj1 = new InstanceInner();
        StaticInner obj2 = new StaticInner();

        // 굳이 접근하려면 아래와 같이 객체를 생성해야 한다.
        // 인스턴스클래스는 외부클래스를 먼저 생성해야만 생성할 수 있다.
        InnerEx2 outer = new InnerEx2();
        InstanceInner obj1 = outer.new InstanceInner();
    }

    void instanceMethod() {
        // 인스턴스메서드에서는 인스턴스멤버와 static멤버 모두 접근 가능하다.
        InstanceInner obj1 = new InstanceInner();
        StaticInner obj2 = new StaticInner();
        // 메서드 내에 지역적으로 선언된 내부클래스는 외부에서 접근할 수 없다.
//      LocalInner lv = new LocalInner();
    }

    void myMethod() {
        class LocalInner { }
        LocalInner lv = new LocalInner();
    }
}

 

 인스턴스클래스는 외부클래스의 인스턴스멤버를 객체생성 없이 바로 사용할 수 있다. (외부클래스의 인스턴스변수가 private일지라도 가능하다.) 그러나 스태틱클래스는 외부클래스의 인스턴스멤버를 객체생성 없이 사용할 수 없다.

 

 마찬가지로 인스턴스클래스는 스태틱클래스의 멤버들을 객체생성없이 사용할 수 있지만, 스태틱클래스에서는 인스턴스클래스의 멤버들을 객체생성없이 사용할 수 없다.

5. 익명클래스(anonymous class)

 익명클래스는 다른 내부클래스들과는 달리 이름이 없다. 클래스의 선언과 객체의 생성을 동시에 하기 때문에 단 한 번만 사용될 수 있고 오직 하나의 객체만을 생성할 수 있는 일회용 클래스이다.

 

new 조상클래스이름( ) {

        // 멤버선언

}

 

또는

 

new 구현인터페이스이름( ) {

        // 멤버선언

}

 

 이름이 없기 때문에 생성자도 가질 수 없으며, 오직 단 하나의 클래스를 상속받거나 단 하나의 인터페이스만을 구현할 수 있다.

 

예제/InnerEx6.java

public class InnerEx6 {
    Object iv = new Object() { void method() { } };         // 익명클래스
    static Object cv = new Object() { void method() { } };  // 익명클래스

    void myMehtod() {
        Object lv = new Object() { void method() { } };     // 익명클래스
    }
}

 

이 예제를 컴파일하면 다음과 같이 4개의 클래스파일이 생성된다.

 

InnerEx6.class

InnerEx6$1.class <-- 익명클래스

InnerEx6$2.class <-- 익명클래스

InnerEx6$3.class <-- 익명클래스

 

익명클래스는 이름이 없기 때문에 '외부 클래스명$숫자.class'의 형식으로 클래스 파일명이 결정된다.

 

 

 

 

출처 | Java의 정석 (남궁 성)

728x90