기초 #11. 중첩 인터페이스와 익명 객체 (+예제 1,2)
중첩 클래스를 다뤘으니 이제 중첩 인터페이스를 다루겠다.
중첩 인터페이스
----------------------------------------------------------------------------------------
▶클래스 내부에 선언한 인터페이스
▶주로 UI 작업을 위한 이벤트에 많이 활용된다.
▶인터페이스를 클래스 내부에 선언하는 이유?
해당 클래스와 긴밀한 관계를 맺는 구현 클래스를 만들기 위해서.
예제
---------------------------------------------------------------------------------------------------------------------------------
1. 내부에 중첩 인터페이스 보유한 클래스 코드
public class Button {
OnClickListener listener; //인터페이스타입 객체
//일반 메서드. 매개변수에 new 형식으로 들어올 듯.
void setOnClickListener(OnClickListener listener) {
this.listener = listener;
}
void touch() { //일반 메서드
listener.onClick();//그 객체의 onClick() 호출
}
interface OnClickListener { //중첩 인터페이스
void onClick(); //추상메서드
}
}
2. 인터페이스 지정한 클래스 2개 코드
public class MessageListener implements Button.OnClickListener { //Button클래스 내부의 인스턴스이기 때문에 Button.OnclickListener
@Override
public void onClick() {
System.out.println("메시지를 보냅니다.");
}
}
public class CallListener implements Button.OnClickListener {
@Override
public void onClick() {
System.out.println("전화를 겁니다.");
}
}
3. 메인 코드
public class ButtonEx {
public static void main(String[] args) {
Button btn = new Button();
btn.setOnClickListener(new CallListener); //this.listener = new CallListener;
btn.touch(); //"전화를 겁니다" 출력
btn.setOnClickListener(new MessageListener); //this.listener = new MessageListener;
btn.touch(); //"메시지를 보냅니다" 출력
}
}
[결과]
익명 객체
----------------------------------------------------------------------------------------
▶이름이 없는 객체
▶new와 동시에 부모클래스를 상속받아 내부에서 오버라이딩한다.
▶익명클래스 내부의 필드를 익명클래스 밖에서 사용할 수 없다.
▶익명 클래스는 언제 사용될까?
상속은 받아야하지만, 한번만 사용할 것이라서 extends 문법을 굳이 사용 안할 때
▶사용 위치
1. 필드의 초기값, 로컬변수의 초기값, 매개변수의 매개값으로 주로 대입. ->초기값 설정에 주목
2. UI 이벤트 처리 객체 / 스레드 객체를 간편하게 생성할 목적으로 주로 활용.
▶익명클래스 내부에는 생성자있을 수 없다.
▶익명객체에서 새롭게 필드와 메서드를 정의할 수 있다.
단, 익명 객체 내부에서만 사용할 수 있고, 외부에서는 익명 객체의 필드/메소드에 접근할 수 없다.
(부모 타입을 오버라이딩한 것만 사용 가능)
▶익명클래스에서는 외부의 자원 중 final 키워드 붙은 요소만을 사용할 수 있다.
▶단독 생성 불가. 클래스를 상속하거나 인터페이스를 구현해야만 생성 가능.
▶[익명 구현 객체 생성 형식]
인터페이스명 변수명 = new 인터페이스명() {
//인터페이스에 선언된 추상 메서드 오버라이딩.
//새로운 필드
//새로운 메서드
};
예제
----------------------------------------------------------------------------------------
1. Person 클래스 코드
public class Person {
void wake() {
System.out.println("익명 객체 구현 전 Person은 8시에 일어납니다.");
}
}
2. Anonymous 클래스 코드
public class Anonymous {
/*필드 초기값으로 대입*/
Person field = new Person() {
void work() {
System.out.println("출근합니다.");
}
void wake() {
System.out.println("field는 6시에 일어납니다.");
work();
}
};
void method1() {
/*로컬 변수값으로 대입*/
Person localVar = new Person() {
void walk() {
System.out.println("산책합니다.");
}
void wake() {
System.out.println("method1()은 7시에 일어납니다.");
walk();
}
};
//로컬변수 사용
localVar.wake(); //localVar 익명객체 안에 구현된 wake()가 호출됨.
}
void method2(Person person) {
Person.wake();
}
}
3. 메인 코드
public class AnonymousEx {
public class static void main(String[] args) {
Anonymous anony = new Anonymous();
anony.field.wake(); //익명객체 필드 사용, filed 익명객체 구현 안에 wake()가 호출됨.
anony.method1(); //익명객체 로컬변수 사용,
//localVar.wake() 문이 수행되어 localVar 익명객체 구현 안에 wake()가 호출됨.
anony.method2(new Person);
//Person타입 객체가 생성되어 person.wake()가 호출되므로 Person클래스에 선언된 wake()가 호출됨.
anony.method2( //익명객체 매개값 사용, 이 안에 구현된 wake()가 호출됨.)
new Person() {
void study() {
System.out.println("공부합니다.");
}
void wake() {
System.out.println("method2()는 8시에 일어납니다.");
study();
}
}
);
}
}
[결과]
예제2 (로컬 변수 사용)
----------------------------------------------------------------------------------------
1. 인터페이스 Calculatable 코드
public interface Calculatable {
public int sum(); //추상메서드
}
2. Anonymous1 클래스 코드
public class Anonymous1 {
private int field;
public void method(final int arg1, int arg2) {
final int var1 = 0;
int var2 = 0;
field = 10;
//arg1 =20; final이니까
//arg2 =20; 왜지?
//var1=30; final이니까
//var2 =30; 왜지?
Calculatable calc = new Calculatable() {
@Override
public int sum() {
int result = field+arg1+arg2+var1+var2;
return result;
}
};
System.out.println(calc.sum());
}
}
3. 메인 코드
public class AnonymousEx1 {
public static void main(String[] args) {
Anonymous1 anony = new Anonymous1();
anony.method(0, 0);
}
}
[결과]