GeehDev

[Java] 이너 클래스 본문

Study/Java

[Java] 이너 클래스

geehyun 2024. 9. 15. 15:31

Index

    반응형

    velog에서 이관해온 글


    이너 클래스

    이너클래스란, 클래스 내부에 포함되는 이너 클래스를 말하며, 아래 3가지로 구분됩니다.

    • 인스턴스 이너클래스
    • 정적(static) 이너클래스
    • 지역 이너클래스

    인스턴스 이너 클래스

    객체 내부의 인스턴스 멤버로 존재하는 이너 클래스 입니다.

    • 자신의 아우터 클래스의 모든 멤버에 마치 자기 것인냥 접근할 수 있습니다. (모든 접근지정자)
    • 컴파일 수행 시 각 클래스별로 바이트 코드로 생성되며 이 때 아우터$이너클래스.class 파일로 생성됩니다.

    객체 생성하기

    //사용법
    아우터클래스 변수명 = new 아우터클래스();
    아우터클래스.이너클래스 변수명 = 아우터변수명.new 이너클래스();
    //사용예시
    class A {
        class B {}
    }
    //-----------------
    A a = new A();
    A.B b = a.new B();        
    //이너클래스의 자료형은 아우터.이너클래스명
    //아우터 클래스의 참조변수를 이용해 생성해야하기 때문에 a.new B()로 작성합니다.
    1. 아우터 클래스의 객체를 생성합니다. => A a = new A();
    2. 아우터 객체의 참조변수 이용해 이너 클래스의 객체를 생성합니다. => A.B b = a.new B();
      이 때 이너클래스의 자료형은 아웃터클래스.이너클래스 입니다. 이는 해당 이너클래스가 바이트코드로 생성될 때 아우터$이너클래스.class 생성되기 때문입니다.

    이너 클래스 내에서 this

    이너클래스와 아우터클래스 에서 필드명 또는 메서드명이 중복될 경우 우선적으로 해당 이너클래스 내에 필드, 메서드를 가져옵니다.
    이 때 아우터의 필드, 메서드를 가져와야할 경우 this 키워드를 사용할 수 있습니다. 다만, 이너클래스도 클래스이기 때문에 this를 사용하면 해당 이너클래스 본인 자신을 가르키기 때문에 아우터클래스명.this로 사용해야합니다.

    class A {
        int a = 4;
        int b = 3;
        class B {
            int a = 5;
            void abc() {
                System.out.println(a);   //이너클래스 내 a 호출 = 5
                System.out.println(this.a);   //이너클래스 내 a 호출 = 5
                System.out.println(A.this.a);   //아우터클래스 내 a 호출 = 4
                System.out.println(b);   //아우터클래스 내 b 호출
            }
        }
    }

    정적 이너 클래스

    이너 클래스 앞에 static 제어자가가 포함된 이너 클래스 입니다.

    • 자신의 아우터 클래스의 멤버 중 정적(statci)멤법에만 접근할 수 있습니다.
    • 컴파일 수행 시 각 클래스별로 바이트 코드로 생성되며 이 때 아우터$이너클래스.class 파일로 생성됩니다.
    • 정적멤버이기 때문에 아우터 클래스 참조 변수 없이 접근할 수 있습니다.

    객체 생성하기

    //사용법
    아우터클래스.이너클래스 변수명 = new 아우터클래스.이너클래스();
    //사용예시
    class A {
        class B {}
    }
    //-----------------
    A.B b = new A.B();        
    //이너클래스의 자료형은 아우터.이너클래스명

    지역 이너 클래스

    클래스의 멤버가 아닌 메서드 내에 정의되는 지역 이너 클래스 입니다.

    • 자신의 아우터 클래스의 모든 멤버에 마치 자기 것인냥 접근할 수 있습니다. (모든 접근지정자)
    • 추가로 자신이 정의된 메서드 내 지역변수도 사용할 수 있으나,
      이 때 접근하는 모든 지역변수는 final 상태여야합니다. (final 아닌 지역변수 접근 시 컴파일러가 강제로 final상태 추가)
    • 해당 지역 이너 클래스가 정의된 메서드 내에서만 객체를 생성할 수 있습니다.
    • 컴파일 수행 시 각 클래스별로 바이트 코드로 생성되며 이 때 아우터$+숫자+이너클래스.class 파일로 생성됩니다. (숫자는 동일한 지역이너클래스 명이 있을 때 +1)

    객체 생성하기

    //사용법
    이너클래스명 변수 = new 이너클래스명();
    
    //사용예시
    class A {
    	void abc() {
        	class B {}
            B b = new B();  //해당 메서드 내에서만 객체 생성 가능
        }
    }
    //-----------------
    A.B b = new A.B();        
    //이너클래스의 자료형은 아우터.이너클래스명
    반응형

    익명 이너 클래스

    익명 이너 클래스는, '이름을 알 수 없는 이너 클래스'를 말합니다.

    //사용법
    클래스명 참조변수명  = new 생성자() {
        접근제어자 리턴타입 메서드명() {
            ...;
        }
    }
    //사용예시
    interface A {
        public abstract void abc();
    }
    class B {
        A a = new A() {       
                //A인터페이스를 상속받아 추상메서드 abc()를 구현하는 익명 이너 클래스
                public void abc() {
                    ...;
                }
        }
        void def() {
            a.abc();
        }
    }
    public class Main {
        public static void main(String[] args) {
            B b = new B();
            b.def(); //b.def() 내에 a.abc() 메서드가 포함되어 있음.
        }
    }

    익명 이너 클래스의 특징

    1. 정적 익명 이너 클래스 존재 불가
    : 인스턴스 익명 이너 클래스, 지역 익명 이너 클래스가 있으며, 정적(static) 익명 이너클래스는 존재할 수 없다.

    정적(static)의 경우 객체 생성없이 사용 가능해야하는데, 익명 이너클래스의 경우 이름이 없기 때문에 객체 생성 불가

    interface A {
        public abstract void abc();
    }
    class B {
        A a = new A() {              // 인스턴스 익명 이너 클래스
                public void abc() {
                    ...;
                }
        }
        void def() {
            A aa = new A() {         // 지역 익명 이너 클래스
                public void abc() {
                    ...;
                }
            }
        }
    }

     

    2. 익명 이너 클래스 내 추가 메서드 작성은 가능 / 해당 이너 클래스 밖에서 사용 불가
    : 익명 이너 클래스에서도 부모클래스(인터페이스)에서 오버라이딩한 메서드 외 추가 정의 메서드를 작성할 수는 있으나, 익명 이너 클래스의 경우 클래스명이 없어 늘 부모 타입으로만 객체 생성이 가능하여, 추가 작성한 메서드는 익명 이너클래스 내부에서만 사용 가능하다.

    interface A {
        public abstract void abc();
    }
    class B {
        A a = new A() {              
                public void abc() {   // 부모 인터페이스의 추상메서드 오버라이딩
                    def();           // 추가 정의 메서드를 내부적으로 호출 가능
                }
                public void def() {  //추가 정의 메서드
                    ...;
                }
        }
        a.abc();  //사용가능
        a.def();  //부모 클래스(인터페이스)에 없는 메서드 익명 이너클래스 밖에서 사용불가
    
    }

    인터페이스 타입의 매개변수에 익명 이너클래스 활용

    인터페이스 타입의 매개 변수란,

    interface A {
        public abstract void abc();
    }
    class B {
        void def(A a) {   //인터페이스 A 타입을 매개변수로 받는 메서드
            a.abc();
        }
    }

    위와 같은 형태로 매개변수로 받는 A 인터페이스를 구현한 자식 클래스의 객체가 매개변수로 전달이 필요한 메서드를 말합니다.

    이 매개변수를 전달하는 방법으로는 4가지 형태가 있습니다.

     

    - 방법 ① : A 인터페이스를 구현한 구현 클래스 작성 후 각 각 객체 생성하여 전달

    class C implements A {
        public void abc() {
            ...;
        }
    }
    B b1 = new B();
    A ac = new C();  //B.def()의 매개 변수가 A타입으로 정의되어있기 때문에 A타입으로 C객체 생성 필요
    bb.def(ac);

     

    - 방법 ② : A 인터페이스를 구현한 구현 클래스 작성 후 new 생성자 이용

    class C implements A {
        public void abc() {
            ...;
        }
    }
    B b2 = new B();
    b2.def(new C());

     

    - 방법 ③ : A 인터페이스를 구현한 익명 이너클래스 작성하여 객체 생성 후 전달

    B b3 = new B();
    A a1 = new A() {
        public void abc() {
            ...;
        }
    }
    b3.def(a1);

     

    - 방법 ④ : 매개변수로 바로 익명 이너 클래스 작성하여 전달

    B b4 = new B();
    b4.def(new A() {
        public void abc() {
            ...;
        }
    });

    방법 ④의 경우 이벤트 처리 시 많이 이용된다고 합니다.

    이너 인터페이스

    인터페이스를 클래스 내부에 정의하는 것을 말합니다. 해당 클래스 내에서 의존적인 기능을 수행할 때 사용할 수 있습니다. (주로 이벤트 처리 시 이용 = '리스너')

    class A {
        static interface B {
            public abstract abc();
        }
    }

    이너 인터페이스의 특징

    1. 정적 이너 인터페이스만 존재할 수 있습니다.
    모든 이너 인터페이스는 정적(static) 인터페이스만 존재할 수 있으며, static 제어자 미입력시 컴파일러가 자동으로 추가해줍니다.

     

    2. 이너 인터페이스도 자체적으로 객체를 생성할 수 있습니다.
    이너 인터페이스도 인터페이스이기 때문에 자체적으로 객체를 생성할 수 없으며, 구현 클래스를 작성 후 구현 클래스의 생성자로 객체 생성 또는 익명 이너 클래스를 활용하여 객체를 생성해줄 수 있습니다.

     

    3. 이너 인터페이스의 객체 타입은 아웃터클래스명.이너인터페이스명 입니다.
    이너 인터페이스의 경우 아웃터 클래스 내부에 위치해 있기 때문에 이너클래스와 유사하게 타입이 아웃터클래스명.이너인터페이스명이 됩니다.

    class A {
        static interface B {
            public abstract abc();
        }
    }
    //구현 클래스 작성
    class C implements A.B {
        //abc 메서드 구현
    }
    C c = new C();
    c.abc();
    
    //익명 이너 클래스 작성
    A.B ab = new A.B() {
        //abc 메서드 구현
    }
    ab.abc();

    참고

    Do it! 진짜 개발자가 되는 Java 프로그램 입문서 자바 완전 정복 - 김동형
    위 책을 공부하며 작성하고 있습니다!

    728x90

    'Study > Java' 카테고리의 다른 글

    [Java] 제네릭  (2) 2024.09.15
    [Java] 예외 처리  (1) 2024.09.15
    [Java] 추상 클래스와 인터페이스  (1) 2024.09.15
    [Java] 자바 제어자 - 접근 제어자/static/일반 제어자  (0) 2024.09.15
    [Java] 클래스의 상속과 다형성  (0) 2024.09.15