[Java] 중첩 클래스와 중첩 인터페이스 ③

kiteB·2022년 1월 24일
0

Java

목록 보기
24/35
post-thumbnail

[ 중첩 인터페이스 ]

중첩 인터페이스는 클래스의 멤버로 선언된 인터페이스를 말한다.
인터페이스를 클래스 내부에 선언하는 이유는 해당 클래스와 긴밀한 관계를 맺는 구현 클래스를 만들기 위해서이다.

class A {
    interface {	//중첩 인터페이스
        void method();
    }
}

[ 익명 객체 ]

익명 객체는 이름이 없는 객체를 말한다.

  • 익명 객체는 단독으로 생성할 수 없고 클래스를 상속하거나 인터페이스를 구현해야만 생성할 수 있다.
  • 익명 객체는 필드의 초기값이나 로컬 변수의 초기값, 매개 변수의 매개값으로 주로 주입된다.

1. 익명 자식 객체 생성

부모 타입으로 필드나 변수를 선언하고 자식 객체를 초기값으로 대입할 경우를 생각해보자.

아래와 같이

  • 부모 클래스를 상속해서 자식 클래스를 선언하여
  • new 연산자를 이용해서 자식 객체를 생성한 후,
  • 필드나 로컬 변수에 대입하는 것이 기본이다.
class Child extends Parent {}	//자식 클래스 선언

class A {
    Parent field = new Child(); //필드에 자식 객체를 대입
    void method() {
        Parent localVar = new Child();  //로컬 변수에 자식 객체를 대입
    }
}

그러나 자식 클래스가 재사용되지 않고, 오로지 해당 필드와 변수의 초기값으로만 사용된다면
익명 자식 객체를 생성해서 초기값으로 대입하는 것이 좋은 방법이다.

📌 익명 자식 객체 생성 방법

부모클래스 [필드|변수] = new 부모클래스(매개값, ...) {
    //필드
    //메소드
}
  • 일반 클래스와의 차이점은 생성자를 선언할 수 없다는 것이다.

예제

  1. 필드를 선언할 때 초기값으로 익명 자식 객체 생성 후 대입
class A {
    Parent field = new Parent() {   //A 클래스의 필드 선언
        int childField;
        void childMethod() { }
        
        @Override   //Parent의 메소드를 오버라이딩
        void parentMethod() { }
    }
}
  1. 메소드 내에서 로컬 변수를 선언할 때 초기값으로 익명 자식 객체 생성 후 대입
class A {
    void method() {
        Parent field = new Parent() {   //로컬 변수 선언
            int childField;
            void childMethod() { }

            @Override   //Parent의 메소드를 오버라이딩
            void parentMethod() { }
        }
        
    }
}

2. 익명 구현 객체 생성

이번에는 인터페이스 타입으로 필드나 변수를 선언하고, 구현 객체를 초기값으로 대입하는 경우를 생각해보자.

아래와 같이

  • 구현 클래스를 선언하고,
  • new 연산자를 이용해서 구현 객체를 생성한 후,
  • 변수나 로컬 변수에 대입하는 것이 기본이다.
class TV implements RemoteControl { }

class A {
    RemoteControl field = new TV(); //필드에 구현 객체를 대입
    void method() {
        RemoteControl localVar = new TV();  //로컬 변수에 구현 객체를 대입
    }
}

구현 클래스가 재사용되지 않고, 오로지 해당 필드와 변수의 초기값으로만 사용하는 경우라면, 역시 익명 구현 객체를 초기값으로 대입하는 것이 좋다.

📌 익명 구현 객체 생성 방법

인터페이스 [필드|변수] = new 인터페이스() {
    //인터페이스에 선언된 추상 메소드의 실체 메소드 선언
    //필드
    //메소드
}

추가적으로 필드와 메소드를 선언할 수는 있지만, 실체 메소드에서만 사용이 가능하고 외부에서는 사용하지 못한다.

예제

  1. 필드를 선언할 때 초기값으로 익명 구현 객체 생성 후 대입
class A {
    RemoteControl field = new RemoteControl() {
        @Override
        void turnOn() { }   //RemoteControl 인터페이스의 추상 메소드에 대한 실체 메소드
    }
}
  1. 메소드 내에서 로컬 변수를 선언할 때 초기값으로 익명 구현 객체를 생성 후 대입
void method() {
    RemoteControl localVar = new RemoteControl() {
        @Override
        void turnOn() { }   //RemoteControl 인터페이스의 추상 메소드에 대한 실체 메소드
    }
}

3. 익명 객체의 로컬 변수 사용

익명 객체 내부에서는 바깥 클래스의 필드나 메소드는 제한 없이 사용할 수 있지만,
매개 변수나 로컬 변수를 익명 객체에 사용할 때 문제가 발생한다!

메소드 내에서 생성된 익명 객체는 메소드 실행이 끝나도 힙 메모리에 존재해서 계속 사용할 수 있는데, 매개 변수나 로컬 변수는 메소드 실행이 끝나면 스택 메모리에서 사라지기 때문에 익명 객체에서 사용할 수 없게 되기 때문이다.

이 문제를 해결하기 위해서는 익명 객체 내부에서 메소드의 매개 변수나 로컬 변수를 사용할 경우 final 특성을 갖도록 해야 한다.

profile
🚧 https://coji.tistory.com/ 🏠

0개의 댓글