본문 바로가기

BackEnd/Java

[java] 이것이 자바다 ch09 중첩 선언 2 및 익명 객체

728x90
반응형

1. 뱌깥 멤버의 접근

 

◎ 바깥 클래스의 멤버 접근 제한

   ▷ 정적 멤버 클래스 내부에서는 바깥 클래스의 필드와 메소드를 사용할 때 제한이 따릅니다.

◎ 바깥 클래스의 사용 가능한 멤버
   ▷ 인스턴스 멤버 클래스 : 바깥 클래스의 모든 필드와 메소드
   ▷ 정적 멤버 클래스 : 바깥 클래스의 정적 필드와 정적 메소드

 

   ▷ 정적 멤버 클래스는 바깥 객체가 없어도 사용 가능해야 하므로 바깥 클래스의 인스턴스 필드와 인스턴스 메소드는 사용하지 못합니다.

 

◎ 바깥 클래스 접근 제한 예제

public class A {
	// A의 인스턴스 필드와 메소드
	int field1;
	void method1() { }
	
	// A의 정적 필드와 메소드
	static int field2;
	static void method2() { }
	
	// 인스턴스 멤버 클래스
	class B{
		void method() {
			// A의 인스턴스 필드와 메소드 사용
			field1 = 10;
			method1();
			
			// A의 정적 필드와 메소드 사용
			field2 = 10;
			method2();
		}
	}
	
	// 정적 멤버 클래스
	static class C{
		void method() {
			// A의 인스턴스 필드와 메소드 사용
			// field1 = 10;
			// method1();
			
			// A의 정적 필드와 메소드 사용
			field2 = 10;
			method2();
		}
	}
}


인스턴스 멤버들은 정적 클래스에서 사용하지 못합니다.
정적 멤버들은 인스턴스 클래스에서 사용하지 못합니다.

 

◎ 바깥 클래스의 객체 접근

   ▷ 중첩 클래스 내부에서 바깥 클래스의 객체를 얻으려면 바깥 클래스 이름에 this를 붙입니다.

바깥클래스이름.this → 바깥 객체

 

◎ 바깥 클래스 객체 접근 예제

1. A 클래스
public class A {
	// A 인스턴스 필드
	String field = "A-field";
	
	// A 인스턴스 메소드
	void method() {
		System.out.println("A-method");
	}
	
	// 인스턴스 멤버 클래스
	class B{
		// B 인스턴스 필드
		String field = "B-field";
		
		// B 인스턴스 메소드
		void method() {
			System.out.println("B-method");
		}
		
		// B 인스턴스 메소드
		void print() {
			// B 객체의 필드와 메소드 사용
			System.out.println(this.field);
			this.method();
			
			// A 객체의 필드와 메소드 사용
			System.out.println(A.this.field);
			A.this.method();
		}
	}
	
	// A의 인스턴스 메소드
	void useB() {
		B b = new B();
		b.print();
	}
}​

 

2. AExample 메인 클래스
public class AExample {
	public static void main(String[] args) {
		// A 객체 생성
		A a = new A();
		
		// A 메소드 호출
		a.useB();
		
	}
}

//	출력 : 
//	B-field
//	B-method
//	A-field
//	A-method​

 

 

2. 중첩 인터페이스

   ▷ 해당 클래스와 긴밀한 관계를 맺는 구현 객체를 만들기 위해 클래스 멤버로 선언된 인터페이스

class A {
	[public | private][static] interface B{
    // 상수 필드
    // 추상 메소드
    // 디폴트 메소드
    // 정적 메소드
    }
}

 

 ▷ 안드로이드 같은 UI 프로그램에서 이벤트를 처리할 목적으로 많이 활용합니다.

public class Button{
	// 정적 중첩 인터페이스
    public static interface ClickListener{
    // 추상 메소드
    void onClick();
    }
}

 

◎ 중첩 인터페이스 예제

1. Button 클래스
public class Button {
	// 정적 중첩 인터페이스
	public static interface ClickListener{
		// 추상 메소드
		void onClick();
	}
	
	// 필드
	private ClickListener clickListener;
	
	// 메소드
	public void setClickListener(ClickListener clickListener) {
		this.clickListener = clickListener;
	}
	
	// 버튼이 클릭되었을 때 실행하는 메소드 선언
	public void click() {
		this.clickListener.onClick();
	}
}​


인터페이스를 통해 onclick이라는 메소드를 만들고 따로 private 변수를 만들어 set을 통해 변수를 클래스로 지정할 수 있게 만들고 click 함수를 통해 인터페이스의 onclick메소드를 부를 수 있습니다.

이때, this.clickListener.onClick()은 clickListener 인터페이스에 있는 onclick 메소드를 지정한다는 말입니다.


2. buttonExample 클래스

public class buttonExample {

	public static void main(String[] args) {
		// OK 버튼 객체 생성
		Button btnOk = new Button();
		
		// Ok 버튼 클릭 이벤트를 처리할 ClickListener 구현 클래스(로컬 클래스)
		class OkListener implements Button.ClickListener{
			@Override
			public void onClick(){
				System.out.println("Ok 버튼을 클릭했습니다.");
			}
		}
		
		// Ok 버튼 객체에 ClickListener 구현 객체 주입
		btnOk.setClickListener(new OkListener());
		
		// Ok 버튼 클릭하기
		btnOk.click();
		
		//------------------------------------------------------
		
		// Cancle 버튼 객체 작성
		Button btnCancel = new Button();
		
		// Cancle 버튼 클릭 이벤트를 처리할 ClickListener 구현 클래스(로컬 클래스)
		class CancelListener implements Button.ClickListener{
			@Override
			public void onClick(){
				System.out.println("Cancel 버튼을 클릭했습니다.");
			}
		}
		
		// Cancel 버튼 객체에 ClickListener 구현 객체 주입
		btnCancel.setClickListener(new CancelListener());
		
		// Cancel 버튼 클릭하기
		btnCancel.click();
	}
}


//	출력 : 
//	Ok 버튼을 클릭했습니다.
//	Cancel 버튼을 클릭했습니다.​


먼저 Button과 관련된 객체를 생성했고 메인 클래스에 로컬 클래스를 생성했습니다.
로컬 클래스에서는 오버라이딩을 하면서 동작할 수 있게 만들어줍니다.

생성한 객체에 CancelListener 객체를 주입하고 버튼을 클릭해서 오버라이딩한 메소드를 불러옵니다.

 

 

3. 익명 객체

   ▷ 이름이 없는 객체, 명시적으로 클래스를 선언하지 않기 때문에 쉽게 객체를 생성할 수 있습니다.

   ▷ 필드 값, 로컬 변수 값, 매개변수 값으로 주로 사용합니다.

 

◎ 익명 자식 객체

   ▷ 부모 클래스를 상속받아 생성되는 객체

   ▷ 부모 타입의 필드, 로컬 변수, 매개변수의 값으로 대입할 수 있습니다.

 

◎ 익명 객체 예제

1. Tire 클래스
public class Tire {
	public void roll() {
		System.out.println("일반 타이어가 굴러갑니다.");
	}
}​

 

2. Car 클래스
public class Car {
	
	// 필드에 Tire 객체 대입
	private Tire tire1 = new Tire();
	
	// 필드에 익명 자식 객체 대입
	private Tire tire2 =new Tire() {
		@Override
		public void roll() {
			System.out.println("익명 자식 Tire 객체 1이 굴러갑니다.");
		}; // 세미콜론을 넣어도 되고 안넣어도 됩니다.
		// 보통 세미콜론을 사용하지 않는 경우가 많습니다.
	};
	// 익명 객체는 마지막에 세미콜론(;)을 붙여줘야합니다.
	
	// tire1과 tire2(익명 자식 객체) 객체 안의 roll() 메서드 실행
	public void run1() {
		tire1.roll();
		tire2.roll();
	}
	
	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();
	}
}​

 

3. CarExample 메인 클래스
public class CarExample {
	public static void main(String[] args) {
		// Car 객체 생성
		Car car = new Car();
		
		// 익명 자식 객체가 대입된 필드 사용
		car.run1();
		
		// 익명 자식 객체가 대입된 로컬변수 사용
		car.run2();
		
		// 익명 자식 객체가 대입된 매개변수 사용
		car.run3(new Tire() {
			@Override
			public void roll() {
				System.out.println("익명 자식 Tire 객체 3이 굴러갑니다.");
			}
		});
	}
}


//	출력 : 
//	일반 타이어가 굴러갑니다.
//	익명 자식 Tire 객체 1이 굴러갑니다.
//	익명 자식 Tire 객체 2가 굴러갑니다.
//	익명 자식 Tire 객체 3이 굴러갑니다.​

 

◎ 익명 구현 객체

   ▷ 인터페이스를 구현해서 생성되는 객체

   ▷ 인터페이스 타입의 필드, 로컬변수, 매개변수의 값으로 대입할 수 있습니다.

   ▷ 안드로이드와 같은 UI 프로그램에서 이벤트를 처리하는 객체로 많이 사용합니다.

 

익명 구현 객체 예제

1. RemoteControl 인터페이스
public interface RemoteControl {
	// 추상 메소드
	void turnOn();
	void turnOff();
}​

 

2. Home 클래스
public class Home {
	// 필드에 익명 구현 객체 대입
	private RemoteControl rc = new RemoteControl() {
		@Override
		public void turnOn() {
			System.out.println("TV를 켭니다.");
		}
		@Override
		public void turnOff() {
			System.out.println("TV를 끕니다.");
		}
	};
	
	// 메소드(필드 이용)
	public void use1() {
		rc.turnOn();
		rc.turnOff();
	}
	// use1은 메모리에 계속 남을 수가 있습니다.
	// 차라리 use2를 사용하면 사용시 객체 생성되었다가 rc가 사라집니다.
	// 메모리 입장에서는 use1 보다는 use2의 방법이 훨씬 낫습니다.
	
	// 메소드(로컬 변수 이용)
	public void use2() {
		// 로컬 변수에 익명 구현 객체 대입
		RemoteControl rc = new RemoteControl() {
			@Override
			public void turnOn() {
				System.out.println("에어컨을 켭니다.");
			}
			@Override
			public void turnOff() {
				System.out.println("에어컨을 끕니다.");
			}
		};
		rc.turnOn();
		rc.turnOff();
	}
	
	public void use3(RemoteControl rc) {
		rc.turnOn();
		rc.turnOff();
	}
}​

 

3. HomeExample 메인 클래스
public class HomeExample {
	public static void main(String[] args) {
		// Home 객체 생성
		Home home = new Home();
		
		// 익명 구현 객체가 대입된 필드 사용
		home.use1();
		
		// 익명 구현 객체가 대입된 로컬 변수 사용
		home.use2();
		
		// 익명 구현 객체가 대입된 매개변수 사용
		home.use3(new RemoteControl() {
			@Override
			public void turnOn() {
				System.out.println("난방을 켭니다.");
			}
			
			@Override
			public void turnOff() {
				System.out.println("난방을 끕니다.");				
			}
		});
	}
}

//	출력 : 
//	TV를 켭니다.
//	TV를 끕니다.
//	에어컨을 켭니다.
//	에어컨을 끕니다.
//	난방을 켭니다.
//	난방을 끕니다.​


use2() 메소드를 사용하면 use1(), use3() 메소드를 사용한 것보다 메모리 부담을 줄일 수 있습니다.
use3()를 사용하면 매개변수가 남기때문에 use1을 사용한 것과 같이 메모리에 남아 부담이 됩니다.

 

 

인터페이스도 클래스와 같이 내부에서 인스턴스 또는 함수, 필드 형태로 만들어서 사용할 수 있습니다.

 

클래스보다는 인터페이스를 많이 사용한다고 하니 참고해서 공부해보시면 좋을 것 같아요!!

 

많은 분들의 피드백은 언제나 환영합니다! 많은 댓글 부탁드려요~~

 

728x90
반응형

'BackEnd > Java' 카테고리의 다른 글

[java] ch11 예외 처리 1  (0) 2023.01.18
[java] 이것이 자바다 ch10 라이브러리와 모듈  (0) 2023.01.17
[java] 이것이 자바다 ch09 중첩 선언  (0) 2023.01.17
[java] 인터페이스2  (0) 2023.01.16
[java] 인터페이스  (2) 2023.01.16