Java/혼공자

Chapter 09 중첩 클래스와 중첩 인터페이스

yeooniyeoon 2023. 1. 20. 00:32
728x90
SMALL

09-1 중첩 클래스와 중첩 인터페이스 소개

중첩 클래스 : 클래스 내부에 선언된 클래스

중첩 클래스 사용 시 두 클래스의 멤버들을 쉽게 접근할 수 있고,

외부에는 불필요한 관계 클래스를 감춰 코드의 복잡성을 낮출 수 있다.

 

중첩 인터페이스 : 클래스 내부에 선언된 인터페이스

해당 클래스와 긴밀한 관계를 맺는 구현 클래스를 만들기 위해 사용한다.

 

 

중첩 클래스

중첩 클래스는 선언되는 위치에 따라 두 가지로 분류된다.

 

멤버 클래스 : 클래스의 멤버로 선언되는 중첩 클래스. 클래스/객체 사용 중에는 언제든 재사용이 가능하다.

로컬 클래스 : 생성자/메소드 내부에 선언되는 중첩 클래스. 메소드 실행 중에만 사용되며 메소드가 종료되면 없어진다.

 

 

인스턴스 멤버 클래스

인스턴스 멤버 클래스는 static 키워드 없이 중첩 선언된 클래스이다.

인스턴스 필드와 메소드만 선언 가능하며 정적 필드, 메소드는 선언이 불가하다.

 

외부에서 중첩 클래스 객체 생성 시 중첩 클래스가 속한 클래스의 객체를 먼저 생성해야 한다.

중첩 클래스가 속한 클래스 내부의 생성자/인스턴스 메소드에서는 일반 클래스처럼 중첩 클래스 객체 생성이 가능하다.

class A {
	class B {
    	B() {}
        int field1;			//인스턴스 필드 선언
        void method() {}		//인스턴스 메소드 선언
        //static field2;		//정적 필드 선언 X
        //static void method2() {}	//정적 메소드 선언 X
   	}
    
    void methodA(){	// A 클래스 내부에선 일반 클래스처럼 B 객체 생성 가능
    	B b = new B();
        b.field1 = 8;
        b.method1();
    }
}
// A 클래스 외부에서 B 객체 생성 시
A a = new A();
A.B b = a.new B();
b.field1 = 2;
b.method1();

하지만 대부분은 내부에서 중첩 클래스 객체를 생성해 사용한다~

 

 

정적 멤버 클래스

정적 멤버 클래스 : static 키워드로 선언된 중첩 클래스

정적 멤버 클래스는 모든 종류의 필드, 메소드를 선언할 수 있다.

외부에서 정적 멤버 클래스 객체를 만드려면 정적 멤버 클래스가 속한 클래스의 객체를 만들 필요는 없고,

바로 정적 멤버 클래스 객체 생성이 가능하다.

class A {
	static class C {
    	int field1;			//인스턴스 필드
        void method1() {}		//인스턴스 메소드
        static int field2;		//정적 필드
        static void method2() {}	//정적 메소드
    }
}
A.C c = new A.C();	//A 객체 생성 없이 바로 C 객체 생성 가능
c.field1 = 5;
c.method1();
A.C.field2 = 30;
A.C.method2();

 

 

로컬 클래스

로컬 클래스 : 메소드 내에 선언된 중첩 클래스

로컬 클래스는 접근 제한자 및 static을 붙일 수 없다

-> 메소드 내부에서만 사용되기 때문에 접근 제한할 필요 X

 

로컬 클래스 내부에는 인스턴스 필드, 메소드만 선언 가능하며

정적 필드, 메소드는 선언할 수 없다.

 

로컬 클래스는 메소드 실행 시 메소드 내부에서 객체를 생성한 뒤 사용해야 한다.

void method() {
	class D {
    	int field1;		//인스턴스 필드
        void method1() {}	//인스턴스 메소드
        // static field2;	정적 필드 선언 X
        // static method2() {}	정적 메소드 선언 X
    }
    
    D d = new D();	//메소드 내부에서 객체 생성하여 사용
    d.field1 = 39;
    d.method1();
}

 

 

중첩 클래스의 접근 제한

바깥 필드와 메소드에서 사용 제한

바깥 클래스에서 인스턴스 멤버 클래스 사용 시 제한이 있다.

인스턴스 멤버 클래스는 바깥 클래스의 인스턴스 필드의 초기값, 인스턴스 메소드에서 객체 생성이 가능하나

바깥 클래스의 정적 필드, 정적 메소드에선 객체 생성이 불가하다.

-> 인스턴스 멤버 클래스 객체는 상위 클래스 객체가 있어야 생성이 가능하기 때문이다.

 

반면 정적 멤버 클래스는 인스턴스/정적 필드와 메소드에서 모두 객체 생성이 가능하다.

 

멤버 클래스에서 사용 제한

인스턴스 멤버 클래스 안에서는 바깥 클래스의 모든 필드, 메소드에 접근이 가능하지만,

정적 멤버 클래스 안에서는 바깥 클래스의 정적 필드, 메소드에는 접근이 가능하나 인스턴스 필드, 메소드에는 접근할 수 없다.

-> 이도 위와 마찬가지로 인스턴스 필드, 메소드는 객체를 생성해야 접근이 가능하기 때문에 정적 멤버 클래스 내부에선 바깥 클래스의 인스턴스 필드, 메소드에 접근할 수 없는 것이다.

 

로컬 클래스에서 사용 제한

자바는 메소드의 매개 변수나 로컬 변수의 값을 로컬 클래스 내부에 복사해두고 사용한다.

그리고 매개 변수나 로컬 변수의 값이 수정될 경우 로컬 클래스에 복사된 값과 달라지므로

이를 해결하기 위해 매개 변수, 로컬 변수를 final로 선언할 것을 요구한다.

 

자바 7 이전에선 final 키워드를 선언하지 않으면 컴파일 에러가 발생했지만

자바 8 이후부터는 final을 명시적으로 선언하지 않아도 자동으로 final 특성을 부여한다.

 

중첩 클래스에서 바깥 클래스 참조 얻기

중첩 클래스 내부에서 this 키워드 사용 시 중첩 클래스 객체 참조를 가리킨다.

중첩 클래스 내부에서 바깥 클래스의 객체 참조를 얻으려면 다음과 같이 사용하면 된다.

바깥클래스.this.필드;
바깥클래스.this.메소드();

 

 

중첩 인터페이스

중첩 인터페이스 : 클래스 내부에 선언된 인터페이스로, 해당 클래스와 긴밀한 관계를 맺는 구현 클래스를 만들기 위해 사용한다.

 

중첩 인터페이스는 인스턴스/정적 멤버 인터페이스 모두 가능하다.

인스턴스 멤버 인터페이스는 바깥 클래스의 객체가 있어야 사용 가능하며,

정적 멤버 인터페이스는 바깥 클래스의 객체 없이도 바깥 클래스만으로 접근이 가능하다.

 

주로 정적 멤버 인터페이스를 많이 사용~

class Button {
	OnClickListener listener;
    
    void setOnClickListener(OnClickListener listener){
    	this.listener = listener;
    }
    
    void touch(){
    	listener.onClick();
    }
    
    static interface OnClickListener {
    	void onClick();
    }
}
public class CallListener implements Button.OnClickListener {
    @Override
    public void onClick(){
    	System.out.println("전화를 겁니다");
    }
}
public class ButtonExam {
	public static void main(String[] args){
    	Button btn = new Button();
        
        btn.setOnClickListener(new CallListener());
        btn.touch();
    }
}

 

 

09-2 익명 객체

익명 객체란 이름이 없는 객체를 말하며 익명 객체는 어떤 클래스를 상속하거나 인터페이스를 구현해야 한다.

 

익명 자식 객체 생성

자식 클래스가 재사용되지 않고 특정 위치에서만 사용될 경우 익명 자식 객체를 사용하면 된다.

부모클래스 필드/변수 = new 부모클래스(매개값) { ... }

매개값은 부모 생성자 매개변수에 맞게 작성하고

중괄호 내부엔 필드와 메소드를 선언과 오버라이딩하는 내용을 작성한다.

생성자는 선언할 수 없다.

class A {
	Parent field1 = new Parent() {	//필드 초기값으로 대입
    	int childField1;
        
        @Override
        void Method() {};
    };
    
    void method() {		//메소드 내부 로컬 변수로 대입
    	Parent field2 = new Parent() {
        	int childField2;
            
            @Override
            void Method() {};
        };
    }
    
    void method2(Person person) {}	//메소드 매개값으로 대입
}

익명 자식 객체에 정의된 필드, 메소드는 내부에서만 사용이 가능하며 외부에선 접근할 수 없다.

-> 익명 자식 객체는 부모 타입 변수에 대입되므로 부모 타입에 선언된 필드와 메소드만 사용 가능하다.

 

 

익명 구현 객체 생성

구현 클래스가 재사용되지 않고 특정 위치에서만 사용될 경우 익명 구현 객체를 생성하는 것이 좋다.

인터페이스 필드/변수 = new 인터페이스() { ... }

중괄호에는 인터페이스에 선언된 추상 메소드들의 실체 메소드를 작성해야 한다.

public class Anonymous {
	RemoteControl field = new RemoteControl() {	//필드 초기값으로 대입
    	@Override
        public void turnOn() { System.out.println("TV를 켭니다"); }
    }
    
    void method1() {	//메소드 내부 로컬 변수로 대입
    	RemoteControl localVar = new RemoteControl() {
        	@Override
            public void turnOn() { System.out.println("Audio를 켭니다"); }
        };
    }
    
    void method2(RemoteControl rc) {	//메소드 매개값으로 대입
    	rc.turnOn();
    }
}

 

 

익명 객체의 로컬 변수 사용

메소드의 매개 변수나 로컬 변수를 익명 객체 내부에서 사용 시 제한이 있다.

중첩 클래스와 같은 문제로 매개 변수나 로컬 변수를 final로 선언해야 한다.

 

역시 자바7 이전 까지는 final 키워드를 붙이지 않으면 컴파일 에러가 발생했지만

자바8 이후부터는 자동으로 final의 특성을 부여한다.

728x90
반응형
SMALL

'Java > 혼공자' 카테고리의 다른 글

Chapter 10 예외 처리  (2) 2023.01.26
Chapter 08 인터페이스  (1) 2023.01.18
Chapter 07 상속  (0) 2023.01.16
[혼공학습단 9기] 혼공자 2주차  (0) 2023.01.15
Chapter 06 클래스  (0) 2023.01.10