GeehDev

[Java] 이너 클래스 본문

Study/Java

[Java] 이너 클래스

geehyun 2024. 9. 15. 15:31

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 프로그램 입분서 자바 완전 정복 - 김동형
위 책을 공부하며 작성하고 있습니다!

'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