본문 바로가기

Programming/자바

자바 재정리 - 중첩 클래스, 중첩 인터페이스

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

 

 

중첩 클래스

 

  •  
인스턴스 멤버 클래스 class A {
    class B{..}
}
A 객체 생성해야만 사용 가능
인스턴스 필드, 메소드만 선언 가능
정적 멤버 클래스 class A {
    static class B{..}
}
A클래스로 바로 접근 가능
모든 종류 필드, 메소드 선언 가능
로컬 클래스 class A {
    void method(){
      class B{..}
  }
}
메소드 내부에서만 사용됨
=> 접근제한자, static 붙일 수 없음
인스턴스 필드, 메소드만 선언 가능

 

 

  •  
public class ClassA { //외부 클래스

    int fieldA;
    
    public ClassA() {
        System.out.println("ClassA가 생성됨");
    }
    
    void methodA() {
        
        //로컬 클래스 (외부클래스의 메소드 내 클래스)
        class ClassD {
        
            int fieldD;
            public ClassD() {
                System.out.println("메서드 안에 있는 로컬클래스 ClassD가 생성됨");
            }
            void methodD() {}
            
        }
    }
    
    
   //인스턴스 내부 클래스 => 인스턴스 필드, 메서드만 선언 가능
    class ClassB{
    
        int fieldB;    
        //static int fieldB2;
        
        public ClassB() {
            System.out.println("ClassB가 생성됨");
        }
     
        void methodB() {}
        
    }
    
   //정적 내부 클래스  => 모든 종류 필드, 메서드 선언 가능
    static class ClassC{

        int fieldC;
        static int fieldC2;
        
        public ClassC() {
            System.out.println("ClassC가 생성됨");
        }
        
        void methodC() {}
        static void methodC2() {}
        
    }
    
}

 

 

  • 내부 인스턴스 클래스
public class NestedClassEx1 {

    public static void main(String[] args) {
        ClassA a = new ClassA();  //ClassA 객체 생성
        a.fieldA=30;
        a.methodA();
        
        //ClassA의 내부클래스 생성(반드시 외부 클래스 생성된 후)
        ClassA.ClassB b = a.new ClassB();  //ClassB 객체 생성
        b.fieldB=50;
        b.methodB();
        
    }
}

 

 

  • 내부 정적 클래스
public class NestedClassEx2 {

    public static void main(String[] args) {
        //내부 정적 클래스 객체 생성 => 외부클래스 객체 필요 X
        ClassA.ClassC c = new ClassA.ClassC(); 
        
        c.fieldC=30;  //인스턴스 필드, 메소드
        c.methodC();
        
        ClassA.ClassC.fieldC2=50;  //정적 필드, 메소드
        ClassA.ClassC.methodC2();
    }

}

 

 

  • 로컬 클래스 : 외부클래스 메소드 안에서만 생성, 사용 가능
public class ClassA {

    int fieldA;
    
    public ClassA() {
        System.out.println("ClassA가 생성됨");
    }
    
    void methodA() {
        
        //로컬 클래스
        class ClassD {
        
            int fieldD;
            
            public ClassD() {
                System.out.println("메서드 안에 있는 로컬클래스 ClassD가 생성됨");
            }
            
            void methodD() {}
            
        }
        
        ClassD d = new ClassD(); //
        d.fieldD=60; //
        d.methodD(); //
       
    }
    
}

 

 

 

 

중첩클래스의 접근 제한
  • 외부클래스에서 사용 제한

인스턴스 멤버클래스 : 외부클래스의 인스턴스 필드, 메소드에서만 초기화 & 객체 생성 가능 

정적 멤버클래스 : 모든 필드에서 초기화, 모든 메소드에서 객체 생성 가능

 

 

  •  
public class ClassA {

    class ClassB{} //인스턴스 멤버클래스
    static class ClassC{} //정적 멤버클래스

    //인스턴스 필드
    ClassB field1 = new ClassB();
    ClassC field2 = new ClassC();

    //인스턴스 메소드
    void method1() {
    	ClassB mtd1 = new ClassB();
        ClassC mtd2 = new ClassC(); 
    }
    
    //정적 필드
    //static ClassB field3 = new ClassB(); //인스턴스 멤버클래스 => 외부 정적 필드 초기화 X
    static ClassC field4 = new ClassC();
    
    //정적 메소드
    static void method2(){
    	//ClassB mtd1 = new ClassB(); //인스턴스 멤버클래스 => 외부 정적 메소드에서 객체 생성 X
        ClassC mtd2 = new ClassC();     
    }

}

 

 

 

 

  • 멤버클래스에서 사용 제한

인스턴스 멤버클래스 : 외부 클래스의 모든 필드, 메소드 접근 가능

정적 멤버클래스 : 외부 클래스의 정적 필드, 메소드에 접근 가능

 

 

  •  
public class ClassA {

    //인스턴스 필드
    int field1;
    void method1(){}
    
    //정적 필드
    static int field2;
    static void method2(){}
    
    //인스턴스 내부 클래스 
    class ClassB{
      
        void method() {
            field1 = 5; 
            method1();
            field2=10;
            method2(); //인스턴스 멤버클래스 => 모든 필드, 메소드 접근 가능
        }
        
    }
    
    
    //정적 내부 클래스 
    static class ClassC{

        void method() {
            //field1 = 5; //정적 멤버클래스 => 인스턴스 메소드, 필드 접근 X
            //method1();
            field2=10;
            method2();
        }
                
    }
       
}
 

 

 
 
  • 로컬클래스에서 사용 제한

외부 클래스의 필드, 메소드 모두 사용 가능

메소드 실행이 끝나면 메소드 매개변수/로컬변수가 스택메모리에서 사라지는 것을 방지하기 위해 로컬클래스 내부에 복사해두고 사용 & final 선언

=> 로컬클래스에서는 final 매개변수, 로컬변수만 사용 가능 (선언 안 해도 final 특성 가짐)

 

 

public class Outer {

	public void method2(int num){ //num: 매개변수
    
    	int localVariable=1; //localVariable: 로컬변수
        //num=10; //값 변경 불가
        //localVariable = 10; //값 변경 불가
        
        class Inner{
        	public void method(){
            	    int result = num + localVariable; //모든 변수 final 특성
            }
        }
        
    }

}

 

 

 

 

  • 중첩클래스에서 외부클래스 참조 얻기

중첩클래스 내부에서 this.필드/메소드 => 중첩클래스의 필드/메소드 사용

외부클래스.this.필드/메소드 => 외부클래스 필드/메소드 사용

 

 

 

 

중첩 인터페이스
class A {

	interface I {
    	    void method();
        }

}

 

 

  • ex
public class Button {
    
    //인터페이스 타입 필드
    OnClickListener listener;
    
    //메서드(매개변수의 다형성)
    void setOnClickListener(OnClickListener listener) {  //매개변수로 인터페이스 받음
        this.listener=listener;
    }
    
    //메서드
    void touch() {
        listener.onClick();
    }
    
    //중첩 인터페이스
    interface OnClickListener{
        void onClick();  //추상메소드
        
    }
}



//구현 클래스
public class CallListener implements Button.OnClickListener{ 

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



//구현 클래스
public class MessageListener implements Button.OnClickListener{ 

    @Override
    public void onClick() {
        System.out.println("문자를 합니다");
    }
}



public class ButtonEx1 {

    public static void main(String[] args) {
        Button btn = new Button();  //인스턴스 객체 생성
        
        btn.setOnClickListener(new CallListener()); 
        btn.touch();
        btn.setOnClickListener(new MessageListener());
        btn.touch();
    
    }
}

//

전화를 겁니다
문자를 합니다

 

 

 

 

익명 객체

: 이름이 없는 객체

 

단독 생성 X / 상속 or 인터페이스 구현해야 생성됨

필드의 초기값, 로컬변수의 초기값, 매개변수의 매개값으로 주로 대입됨

 

끝에 세미콜론

생성자 선언 불가

익명 자식 객체에서 새로 정의된 필드, 메소드는 내부에서만 사용 가능

 

 

  • (상속) 익명 자식 객체 생성
  •  
//필드 선언
//class Child extends Parent {}
//
//class A {
//    Parent field = new Child(); //필드에 자식객체 대입
//    void method(){
//        Parent localVar = new Child(); //로컬변수에 자식객체 대입
//    }
//}


//필드 선언 시 초기값으로 익명자식객체 대입
class A {

	void method(){
    
		Parent localVar = new Parent(){ //익명 자식 객체 생성, 대입
			int childField;
			void childMethod();
			@Override
			void parentMethod(){} //부모클래스 메소드 오버라이딩
		};
        
	}

}


//메소드 매개변수가 부모타입일 때, 매개값으로 익명자식객체 대입
class A {

	void method1(Parent parent){}

	void method2(){
		
		method1(
			new Parent(){ //method1 매개값으로 익명 자식 객체 대입
				int childField;
				void childMethod();
				@Override
				void parentMethod(){} 
			}
		);
        
	}

}

 

 

  •  
public class Person {

    void wake() {
        System.out.println("7시에 일어납니다");
    }
    
}


public class Anonymous {

    Person pField=new Person() { //필드에 대입
        
        void walk() {
            System.out.println("산책합니다");
        }
        
        @Override
        void wake() {
            System.out.println("6시에 일어납니다");
            walk();
        }
        
    };
    
    //메서드
    void method1(Person person) { //매개값으로 대입
        person.wake();
    }
    
    void method2() {
        
        Person localPerson = new Person() { //로컬변수에 대입
            void study() {
                System.out.println("공부합니다");
            }
            void wake() {
                System.out.println("7시에 일어납니다");
                study();
            }
            
        };
        
        localPerson.wake(); //로컬변수 사용
    }
    
}


public class AnonymousEx1 {

    public static void main(String[] args) {
    
        Anonymous anon = new Anonymous();  //인스턴스 객체 생성
        
        anon.pField.wake(); //필드 대입
        
        anon.method1(new Person() { //매개값 대입
            void work() {
                System.out.println("출근합니다");
            }
            
            @Override
            void wake() {
                System.out.println("8시에 일어납니다");
                work();
            }
        });
        
        anon.method2(); //로컬변수 대입
        
    }
}

//
6시에 일어납니다
산책합니다
8시에 일어납니다
출근합니다
7시에 일어납니다
공부합니다

 

 

 

 

  • (인터페이스) 익명 구현 객체 생성
  •  
public interface RemoteControl {
    void turnOn();
    void turnOff();
}
public class Anonymous {

    //필드 초기값으로 대입
    RemoteControl TV = new RemoteControl() {
        @Override
        public void turnOn() {
            System.out.println("TV를 켭니다.");
        }

        @Override
        public void turnOff() {
            System.out.println("TV를 끕니다.");
        }
    };

    void method1(){
        //로컬 변수값으로 대입 
        RemoteControl audio = new RemoteControl() {
            @Override
            public void turnOn() {
                System.out.println("오디오를 켭니다.");
            }

            @Override
            public void turnOff() {
                System.out.println("오디오를 끕니다.");
            }
        };
        //로컬 변수 사용
        audio.turnOn();
        audio.turnOff();
    }
    
    //매개값으로 대입 (예정)
    void method2(RemoteControl remoteControl){
        remoteControl.turnOn();
        remoteControl.turnOff();
    }
}
public class AnonymousEx {

    public static void main(String[] args) {
        Anonymous an = new Anonymous();

        //익명 객체 필드 사용
        an.TV.turnOn();
        an.TV.turnOff();

        //익명 객체 메소드 사용
        an.method1();

        //매개변수로 익명 객체 대입
        an.method2(new RemoteControl() {
            @Override
            public void turnOn() {
                System.out.println("자동차를 켭니다.");
            }

            @Override
            public void turnOff() {
                System.out.println("자동차를 끕니다.");
            }
        });
    }
}

//

TV를 켭니다.
TV를 끕니다.
오디오를 켭니다.
오디오를 끕니다.
자동차를 켭니다.
자동차를 끕니다.

'Programming > 자바' 카테고리의 다른 글

자바 재정리 - API  (0) 2022.09.05
자바 재정리 - 예외 처리  (0) 2022.08.26
자바 재정리 - 인터페이스  (0) 2022.08.25
자바 재정리 - 상속  (0) 2022.08.23
자바 재정리 - 클래스  (0) 2022.08.11