JAVA 8주차

ndy·2022년 11월 16일

Java

목록 보기
8/10

9장 중첩 선언과 익명 객체

9.1 중첩 클래스

  • 클래스 내부에 선언한 클래스
  • 코드의 복잡성을 줄임

맴버 클래스

  • 클래스 맴버로 선언되는 중첩 클래스
// 인스턴스 맴버 클래스
class A {
	class B {...}	// A객체를 생성해야 B객체 생성 가능
}

// 정적 맴버 클래스
class A {
	static class B {...}	// A객체를 생성하지 않아도 B객체 생성 가능
}
  • 바이트코드 파일

    	 A$B.class

로컬 클래스

  • 메소드 내부에서 선언되는 중첩 클래스
class A {
	void method() {	// method가 실행할 때만 B객체 생성 가능
    	class B {...}
    }
}
  • 바이트코드 파일

    	A$1B.class

9.2 인스턴스 맴버 클래스

[public] class A {
	[public | private] class B {...}
}
  • 접근 제한자
구분접근범위
public class B다른 패키지에서 B클래스 사용 가능
(default) class B같은 패키지에서만 B클래스 사용 가능
private class BA 클래스 내에서만 B 클래스 사용 가능
public class A {
	// 인스턴스 맴버 클래스
	class B {
    	public void methodB(){...}
    }
    
    // 인스턴스 필드 값으로 B객체 대입
    B field = new B();
    
    // 생성자
    A() {
    	B b = new B();
    }
}
// 클래스 B 객체 사용
public class AExample {
	public static void main(String[] args) {
    	A a = new A();	// A 클래스 객체 생성
        A.B b = a.new B(); // A 객체 안의 B 클래스 객체 생성
        b.methodB(); // B 객체의 메소드 실행
    }
}

9.3 정적 맴버 클래스

[public] class A {
	[public | private] static class B {...}
}
  • 접근 제한자
구분접근범위
public static class B다른 패키지에서 B클래스 사용 가능
(default) static class B같은 패키지에서만 B클래스 사용 가능
private static class BA 클래스 내에서만 B 클래스 사용 가능
public class A {
	// 인스턴스 맴버 클래스
	static class B {
    	public void methodB(){...}
    }
    
    // 인스턴스 필드 값으로 B객체 대입
    B field1 = new B();
    
    // 정적 필드 값으로 B객체 대입
    static B field2 = new B();
    
    // 생성자
    A() {
    	B b = new B();
    }
    
    // 인스턴스 메소드
    void method1() {
    	B b = new B();
    }
    
    static void method2() {
    	B b = new B();
    }
}
// 클래스 B 객체 사용
public class AExample {
	public static void main(String[] args) {
        A.B b = new A.B(); // B 객체 생성 
        // (A 객체를 생성하지 않아도 B 클래스 사용가능)
        
        b.methodB(); // B 객체의 메소드 실행
    }
}

9.4 로컬(local) 클래스

로컬 클래스의 예시

public class A {
	//생성자 안에 클래스 B 선언
	public A() {
    	class B {...} // 접근 제한자 불가능 (외부 접근 x)
        
        //객체 생성
        B b = new B();
    } // A() 생성자 외부에서 클래스 C 사용불가
    
    
    //메소드 안에 클래스 C 선언
    void method() {
    	class C {...} // 접근 제한자 불가능 (외부 접근 x)
        
        //객체 생성
        C c = new C();
    } // method() 메소드 외부에서 클래스 C 사용불가
}

Ex2)

  • 로컬 변수로컬 클래스 안에서 사용할 경우 로컬 변수final 특성을 가짐
public class A {
	public method(int arg) {
    	// 로컬 변수 선언
    	int var = 1;
        
        // 로컬 클래스 B 선언
        class B { 
        	void method_B() {
            	//로컬 변수 읽기
            	System.out.println("arg: " + arg); (o)
                System.out.println("var: " + var); (o)
                
                //로컬 변수 수정
                arg = 2; // (x) 
                var = 2; // (x)
                // fianl 변수 변경 불가
            }
        }
        
        B b = new B();		//로컬 객체 생성
        b.method_B();	//로컬 객체 메소드 호출
        
        arg = 3; // (x)
        var = 3; // (x)
        // 로컬 클래스 안에서 로컬 변수를 사용하고 있기 때문에 변경 불가
    }
}

9.5 바깥 맴버 접근

구분바깥 클래스의 사용 가능한 맴버
인스턴스 맴버 클래스바깥 클래스의 모든 필드와 메소드
정적 맴버 클래스바깥 클래스의 정적 필드와 정적 메소드
public class A {
	// A 클래스의 인스턴스 필드, 메소드 (A객체가 있어야 사용 가능)
	int field_instance;
    void method_instance() {...}
    
    // A 클래스의 정적 필드, 메소드 (A객체가 없어도 사용 가능)
    static int field_static;
    static void method_static() {...}
    
    // 인스턴스 맴버 클래스 B (A객체가 있어야 사용 가능)
    class B {
    	void method_B(){
        	// A의 인스턴스 필드, 메소드 사용
            field_instance = 10;
            method_instance();
        }
    }
    
    // 정적 맴버 클래스 (A객체가 없어도 사용 가능)
    static class C {
    	void method() {
        	// A의 정적 필드, 메소드 사용
            field_static = 10;
            method_static();
        }
    }
}

바깥 클래스의 객체 접근

public class A {
    
    //A의 인스턴스 메소드
    void method() {
    	System.out.println("A"); // A 출력
    }
    
    //인스턴스 맴버 클래스 B 선언
    class B {
    	//B의 인스턴스 메소드
        void method() {
    		System.out.println("B"); // B 출력
    	}
        
        //B의 인스턴스 메소드
       	void print() {
        	//B 객체의 메소드 사용
        	this.method();
            
            //A 객체의 메소드 사용
            A.this.method();
        }
    }
    
    //A의 인스턴스 메소드
    void useB() {
    	B b = new B();
        b.print();
    }
}

9.6 중첩 인터페이스

  • 인터페이스를 클래스 내부에 선언하는 이유는 해당 클래스와 긴밀한 관계를 맺는 구현 객체를 만들기 위함
	class A {
    	[public | private] [static] interface B {
        	// 상수 필드
            // 추상 메소드
            // 디폴트 메소드
            // 정적 메소드
        }
    }
  • 중첩 인터페이스는 안드로이드와 같은 UI 프로그램에서 이벤트를 처리할 목적으로 많이 활용
public class Button {
	public static interface ClickListener {
    	// 추상 메소드
        void onClick();
    }
    
    // 필드
    private ClickListener clickListener;
    
    // 메소드
    // 매개변수 타입이 인터페이스이므로 ClickListener 인터페이스를 구현한 객체를 대입
    public void setClickListener(ClickListener clickListener) { 
    	this.clickListener = clickListener;
    }
    
    public void click() {
    	this.clickListener.onClick();
    }
}

Button 클래스 이용 예제

public class ButtonExample {
	public static void main(String[] args) {
    	//Ok 클릭 버튼 생성
        Button btnOk = new Button();
        
        class OkListener implements Button.ClickListener {
        	// 추상 메소드 구현하기
        	@override
            public void onClick() {
            	System.out.println("Ok 버튼을 클릭했습니다.");
            }
        }
        
        // Button 클래스 객체의 setClickListener() 메소드에 
        // ClickListener 인터페이스를 구현한 OkListener 클래스 객체를 대입
        btnOk.setClickListener(new OkListener);
        
        // Button 클래스 객체의 click() 메소드 호출
        btnOk.click(); //"Ok 버튼을 클릭했습니다." 출력
    }
}

9.7 익명 객체

  • 익명 객체는 클래스를 상속하거나 인터페이스를 구현해야만 생성할 수 있음
  • 클래스를 상속해서 만들면 익명 자식 객체
  • 인터페이스를 구현해서 만들면 익명 구현 객체

익명 자식 객체

new 부모생성자(매개값, ...) { // 부모클래스를 상속 받는 익명 자식클래스를 만듦 
	// 필드
    // 메소드
}

ex)

  • Tire.java
public class Tire {
	public roll() {
    	System.out.println("일반 타이어가 굴러갑니다.");
    }
}
  • Car.java
public class Car {
	// 필드에 Tire 객체 대입
	private Tire tire1 = new Tire();
	
    // 필드에 익명 자식 객체 대입
	private Tire tire2 = new Tire() { // Tire를 상속 받은 익명 자식클래스를 만들어 대입
    	@Override
        public void roll() {
        	System.out.println("익명 자식 Tire 객체 1이 굴러갑니다.");
        }
    };
    
    // 메소드(필드 이용)
    public void run1() {
    	tire1.roll(); // "일반 타이어가 굴러갑니다." 출력
    	tire2.roll(); // "익명 자식 Tire 객체 1이 굴러갑니다." 출력
    }
    
    // 메소드(로컬 변수 이용)
    public void run2() {
    	Tire tire = new Tire() {
        	@Override
            public void roll() {
            	System.out.println("익명 자식 Tire 객체 2가 굴러갑니다.");
            }
        }
        tire.roll();
    }
    
    // 메소드(매개변수 이용)
    public void run3(Tire tire) {
    	tire.roll();
    }
}
Car car = new Car();

// 익명 자식 객체가 대입된 매개변수 사용
car.run3(new Tire() {
	@Override
    public void roll() {
    	System.out.println("익명 자식 Tire 객체 3이 굴러갑니다.");
    }
});

익명 구현 객체

new 인터페이스() { // 인터페이스를 구현한 익명 클래스를 만듦
	// 필드
    // 메소드
}

ex)

  • RemoteControl.java
public interface RemoteControl {
	// 추상 메소드
    void turnOn();
}
  • Home.java
public class Home {
	// 필드에 익명 구현 객체 대입
    private RemoteControl rc = new RemoteControl() {
    	@Override
        public void turnOn() {
        	System.out.println("TV를 켭니다.");
        }
    }
    
    // 메소드(필드 이용)
    public void use1() {
    	rc.turnOn(); // "TV를 켭니다." 출력
    }
    
    // 메소드(로컬 변수 이용)
    public void use2() {
    	//로컬 변수에 익명 구현 객체 대입
        RemoteControl rc = new RemoteControl() {
        	@Override
        	public void turnOn() {
        		System.out.println("에어컨을 킵니다.");
          	}
        };
        
        rc.turnOn(); // "에어컨을 킵니다." 출력
    }
    
    // 메소드(매개변수 이용)
    public void use3(RemoteControl rc) {
    	rc.turnOn();
    }
}
Home home = new Home();

// 익명 구현 객체가 대입된 매개변수 사용
home.use3(new RemoteControl() {
	@Override
    public void turnOn() {
  		System.out.println("난방을 킵니다.");
    }
});

0개의 댓글