본문 바로가기

프로그래밍/Java

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

중첩 클래스

클래스 내부에 선언한 클래스

 

중첩 클래스

class ClassName{
	class NestedClassName{
    }
}

 

중첩 인터페이스

class ClassName{
	interface NestedInterfaceName{
    }
}

 

선언 위치에 따른 분류 선언 위치 설명
멤버 클래스

인스턴스

멤버 클래스

class A{

    class B{...}

}

A 객체를 생성해야만

사용할 수 있는 B 클래스

정적

멤버 클래스

class A{

    static class B{...}

}

A 클래스로 바로 접근할 수

있는 B 클래스

로컬 클래스

class A{

    void method(){

        class B{...}

    }

}

method()가 실행할 때만

사용할 수 있는 B 클래스

 

인스턴스 멤버 클래스

A 클래스 내부 중첩 클래스인 B 클래스의 객체 생성 법

 

A 클래스 내부

public class A{
    class B{
        int field;
        void method(){};
    }
    
    B b = new B();
    b.field = 3;
    b.method();
}

 

A 클래스 외부

public class Test{
    public static void main(String[] args){
        A a = new A();
        A.B b =a.new B();
        b.field = 4;
        b.method();
    }
}

 

대부분 A클래스 내부에서 사용

 

 

정적 멤버 클래스

A 클래스 외부에서 사용한데도 A객체를 생성할 필요X

public class A{
    static class B{
        int field1;
        static int field2;
        void method1(){};
        static void method2(){};
    }
}
public class Test{
    public static void main(String[] args){
        A.B b = new A.B();
        b.field1 = 4;
        b.method1();
        A.B.field2 = 3;
        A.B.method2();
    }
}

 

 

 

로컬 클래스

public class A{
    void methodA(){
        class B{
            int field1;
            void method1(){};
        }
        B b = new B();
        b.field1 = 5;
        b.method1();
    }
}

 

 

 

 

 

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

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

정적 멤버 클래스(C)는 모든 필드의 초기값이나 모든 메소드에서 객체 생성 가능

public class A{
    class B{}//인스턴스 멤버 클래스
    static class C{}//정적 멤버 클래스
    
    B field1 = new B();//인스턴스 필드
    C field2 = new C();//인스턴스 필드
    //static B field3 = new B(); ERROR 정적 필드
    static C field4 = new C();//정적 필드
    
    void method1(){//인스턴스 메소드
        B var1 = new B();
        C var2 = new C();
    }
    static void method2(){//정적 메소드
        //B var1 = new B(); ERROR
        C var2 = new C();
    }
}

 

 

 

멤버 클래스에서 사용제한

인스턴스 멤버 클래스(B) 안에서는 바깥 클래스의 모든 필드와 메소드에 접근 가능

정적 멤버 클래스(C) 안에서는 정적 필드와 정적 메소드만 접근 가능

public class A{
    int field1;//인스턴스 필드
    void method1(){}//인스턴스 메소드

    static int field2;//정적 필드
    static void method2(){}//정적 메소드

    public class B{//인스턴스 멤버 클래스
        void method(){
            field1 = 10;
            method1();
            
            field2 = 10;
            method2();
        }
    }
    
    static class C{//정적 멤버 클래스
        void method(){
            //field1 = 10; ERROR
            //method1(); ERROR
            
            field2 = 10;
            method2();
        }
    }
}

 

 

로컬 클래스에서 사용제한

로컬 클래스는 메소드 안에 존재하기 때문에

그 메소드가 종료되면 사라지는게 일반적이지만

메소드가 종료되어도 계속 실행 상태로 존재할 수 있음(로컬 스레드 객체)

 

이때 자바는 로컬 클래스에서 사용하는

로컬 클래스를 포함하는 메소드의 매개변수 OR 로컬 변수값을

로컬 클래스 내부에 복사해두고 사용

 

그리고 매개변수나 로컬변수가 수정되어 값이 변경되면

로컬 클래스에 복사해둔 값과 달라지므로

매개변수나 로컬 변수는 final로 선언요구(자바 8이후에는 생략해도 붙음)

public class A{
    void method1(int arg){
        int localVal = 10;
        arg = 100;
        localVal = 20;
    }
    
    void method2(int arg){//final이 생략됐지만 자동 final
        int localVal = 10;//final이 생략됐지만 자동 final
        //arg = 100; ERROR
        //localVal = 20; ERROR
        class Inner{//로컬 클래스
            void method(){
                int result = arg+localVal;
            }
        }
    }
}

 

 

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

중첩 클래스에서 바깥 클래스의 객체 참조

바깥클래스.this.필드

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

public class A{
    String field = "바깥 클래스 필드";
    void method(){
        System.out.println("바깥 클래스 메소드");
    }
    
    class B{
        String field = "중첩 클래스 필드";
        void method(){
            System.out.println("중첩 클래스 메소드");
        }
        
        void print(){
            System.out.println(this.field);//중첩 객체 참조
            this.method();//중첩 객체 참조
            
            System.out.println(A.this.field);//바깥 객체 참조
            A.this.method();//바깥 객체 참조
        }
    }
}
public class Test{
    public static void main(String[] args){
        A a = new A();
        A.B b = a.new B();
        
        b.print();
    }
}

Test 실행결과

 

 

 

중첩 인터페이스

클래스의 멤버로 선언된 인터페이스

class A{
	interface I{
    	void method();
    }
}

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

인스턴스 멤버 인터페이스와 정적 멤버 인터페이스 둘 다 가능

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

 

예제)

Button을 클릭했을 때 이벤트를 처리하는 객체를 받고 싶다

Button 내부에 선언된 중첩 인터페이스를 구현한 객체만 맏고 싶다

 

Button 클래스와 중첩 인터페이스 OnClickListener

public class Button{
    static interface OnClickListener{//중첩 인터페이스
        void onClick();
    }
    
    OnClickListener listener;//인터페이스 타입 필드
    
    void setOnClickListener(OnClickListener listener){//매개변수의 다형성
        this.listener = listener;
    }
    
    void touch(){
        listener.onClick();//구현 객체의 onClick메소드 호출
    }
}

구현 객체1 CallListener

public class CallListener implements Button.OnClickListener{
    @Override
    public void onClick(){
        System.out.println("전화를 겁니다.");
    }
}

구현 객체2 MessageListener

public class MessageListener implements Button.OnClickListener{
    @Override
    public void onClick(){
        System.out.println("메세지를 보냅니다");
    }
}

실행 클래스 ButtonTest

public class ButtonTest{
    public static void main(String[] args){
        Button btn = new Button();
        
        btn.setOnClickListener(new CallListener());
        btn.touch();
        
        btn.setOnClickListener(new MessageListener());
        btn.touch();
    }
}

ButtonTest 실행 결과

'프로그래밍 > Java' 카테고리의 다른 글

예외 클래스  (0) 2019.12.07
익명객체  (0) 2019.12.06
인터페이스  (0) 2019.12.04
추상 클래스  (0) 2019.12.04
타입 변환과 다형성  (0) 2019.12.04