728x90
익명 객체란 ?
- 말 그대로 이름이 없는 객체이다.
- 보통 우리는 클래스를 생성하고 여러 곳에서 그 클래스를 가지고 객체를 만든다.
- new 연산자를 통해 클래스이름으로 생성자를 호출하는 방법을 사용한다.
- 여기서 우리는 여러 곳에서 사용하지 않고 오로지 특정 위치에서만 사용하고 싶을 때가 있다.
- 그 한 번의 사용을 위해 굳이 클래스를 만들어 사용하는 것은 귀찮은 일이다.
- 이럴 때 우리는 익명 객체를 사용하여 클래스를 명시적으로 선언하지 않고 바로 객체를 생성할 수 있다.
- 인터페이스를 구현할 때도 익명 객체 생성 가능
일반적인(명시적으로 선언) 객체 생성 방법과 익명 자식 객체 생성 방법의 차이점
- 명시적인으로 객체 생성 방법
class Parent {} // 부모 클래스 생성
class Child extends Parent {} // 자식 클래스 생성
public class Example {
// 필드의 초기값으로 자식 객체를 대입
Parent field = new Child();
// 로컬 변수로 자식 객체를 대입
void method() {
Parent localVar = new Child();
}
}
- 익명 객체를 사용하는 방법
// 부모 클래스 생성
class Parent {
void parentMethod() {}
}
// 상속을 통해 객체 생성 - 익명 객체를 사용하는 방법
class Example2 {
// 방법 1. 필드 선언
Parent field = new Parent() { // 부모 생성자를 호출하는 코드
// 부모 클래스를 상속해서 중괄호 안에 있는 내용처럼 자식 클래스를 선언한다는 의미
int childField; // 필드나 메소드선언
void childMethod() {}
@Override // 부모 메소드를 재정의
void parentMethod() {
childField = 3; // 익명 자식 객체에서 정의된 필드와 메소드는
childMethod(); // 익명 자식 객체 안에서만 사용 가능함
} // 이유는 익명 자식 객체가 부모 타입 변수에 대입되어 부모 타입에 선언된것만 사용 가능하기 때문
};
void method_cannot_use_anonymous() {
// field.childField = 3; // 익명 자식 객체 외부에서는 필드나 메소드 사용 불가
// field.childMethod(); // parentMethod() 내부에서는 사용 가능
field.parentMethod(); // 부모 메소드 호출은 가능
}
// 방법 2. 로컬 변수 선언 (방법1과 차이점은 메소드안에서 생성한다는 것만 다름)
void method() {
Parent localVar = new Parent() {
int childField;
void childMethod() {}
@Override
void parentMethod() {} // 부모 메소드를 재정의
};
}
// 방법 3. 매개 값으로 익명 객체 대입
void method1(Parent parent) {} // 매개변수를 갖는 메소드 선언
void method2() { // method1()을 호출
method1( // method1()의 매개 값으로 익명 객체 대입
new Parent() {
int childField;
void childMethod() {}
@Override
void parentMethod() {}
}
);
}
}
익명 자식 객체 생성 예제
<부모 클래스 생성>
class Person {
void wake() {
System.out.println("6시에 일어납니다.");
}
}
<익명 자식 객체 생성할 클래스 생성>
public class Anonymous {
// 방법 1. 필드의 초기값으로 대입
Person field = new Person() {
void work() {
System.out.println("출근합니다.");
}
@Override
void wake() {
System.out.println("6시에 일어납니다.");
work();
}
};
// 방법 2. 로컬 변수로 대입
void method1() {
//로컬 변수 생성
Person localVar = new Person() {
void walk() {
System.out.println("산책합니다.");
}
@Override
void wake() {
System.out.println("7시에 일어납니다.");
walk();
}
};
// 로컬 변수 사용
localVar.wake();
}
// 방법 3. 매개 값으로 대입
void method2(Person person) {
person.wake();
}
}
<익명 자식 객체를 이용하여 메소드 호출>
public class AnonymousExample {
public static void main(String[] args) {
// 객체 부터 생성
Anonymous anony = new Anonymous();
// 방법 1 사용. 필드 사용
anony.field.wake(); // 6시에 일어납니다. 출근합니다.
// 방법 2 사용. 로컬 변수 사용
anony.method1(); // 7시에 일어납니다. 산책합니다.
// 방법 3 사용. 매개변수로 대입하여 사용
anony.method2(
new Person() {
void study() {
System.out.println("공부합니다.");
}
@Override
void wake() {
System.out.println("8시에 일어납니다.");
study();
}
}
); // 8시에 일어납니다. 공부합니다.
}
}
인터페이스를 사용하여 익명 구현 객체 생성
- 일반적인 객체 생성 방법
interface RemoteControl {}
class TV implements RemoteControl {} // 구현 클래스 선언
public class Example_interface { // 일반적인 방법은 이렇게 A라는 클래스를 명시한 후 사용함
RemoteControl field = new TV(); // 구현 객체 생성 후 인터페이스 타입의 필드에 대입
void method() {
RemoteControl localVar = new TV(); // 구현 객체 생성 후 인터페이스 타입의 로컬 변수에 대입
}
}
- 익명 구현 객체 생성하는 방법
public class Example_interface2 {
// 방법 1. 필드의 초기값으로 익명 구현 객체를 생성해서 대입하기
RemoteControl field = new RemoteControl() {
// new 연산자를 통해 중괄호 내부와 같이 선언된 구현 클래스를 객체로 생성한다.
@Override
public void turnOn() {} // 추상 메소드를 재정의한 실체 메소드
};
// 방법 2. 메소드 내에서 로컬 변수를 선언할 때 초기값으로 익명 구현 객체를 생성해서 대입
void method() {
RemoteControl localVar = new RemoteControl() {
@Override
public void turnOn() {}
// 구현 객체 생성 후 인터페이스 타입의 로컬 변수에 대입
};
}
// 방법 3. 메소드의 매개 값으로 익명 구현 객체를 생성해서 대입
void method1(RemoteControl rc) {}
void method2() {
method1( // method1 호출
new RemoteControl() { // method1() 매개값으로 익명 구현 객체를 대입
@Override
public void turnOn() {}
}
);
}
}
익명 구현 객체 생성 예제
interface RemoteControl {
public void turnOn();
public void turnOff();
}
public class Anonymous2 {
// 방법 1. 필드의 초기값으로 익명 구현 객체를 생성해서 대입하기
RemoteControl field = new RemoteControl() {
@Override
public void turnOn() {
System.out.println("TV를 켭니다.");
}
@Override
public void turnOff() {
System.out.println("TV를 끕니다.");
}
};
// 방법 2. 메소드 내에서 로컬 변수를 선언할 때 초기값으로 익명 구현 객체를 생성해서 대입
void method1() {
RemoteControl localVar = new RemoteControl() { // 로컬 변수 선언
@Override
public void turnOn() {
System.out.println("Audio를 켭니다.");
}
@Override
public void turnOff() {
System.out.println("Audio를 끕니다.");
}
};
localVar.turnOn(); // 로컬 변수 사용
localVar.turnOff();
}
// 방법 3. 메소드의 매개 값으로 익명 구현 객체를 생성해서 대입
void method2(RemoteControl rc) {
rc.turnOn();
rc.turnOff();
}
}
public class Anonymous2Example {
public static void main(String[] args) {
Anonymous2 anony = new Anonymous2(); // 객체 생성
// 1. 익명 객체 필드 사용
anony.field.turnOn();
anony.field.turnOff();
System.out.println();
// 2. 익명 객체 로컬 변수 사용
anony.method1();
System.out.println();
// 3. 익명 객체 매개값 사용
anony.method2(new RemoteControl() {
@Override
public void turnOn() {
System.out.println("Smart TV를 켭니다.");
}
@Override
public void turnOff() {
System.out.println("Smart TV를 끕니다.");
}
}
);
}
}
TV를 켭니다.
TV를 끕니다.
Audio를 켭니다.
Audio를 끕니다.
Smart TV를 켭니다.
Smart TV를 끕니다.
UI 프로그램에서 버튼의 클릭 이벤트 처리 예제 ( 익명 구현 객체를 이용 )
<Button 클래스>
public class Button {
static interface OnClickListener {
void onClick();
} // 중첩 인터페이스 선언
OnClickListener listener; // 인터페이스 타입 필드 선언
// setter 메소드로 외부에서 구현 객체 받아 필드에 대입
void setOnClickLister(OnClickListener listener) {
this.listener = listener;
}
// touch를 하면 인터페이스를 통해 구현 객체의 메소드인 onClick()이 호출됨
void touch() {
listener.onClick();
}
}
<Window 클래스>
public class Window {
// 윈도우에는 두 개의 버튼이 있으므로 2개의 Button 객체 생성
Button button1 = new Button();
Button button2 = new Button();
// button1의 클릭 이벤트 처리는 필드로 선언한 익명 구현 객체가 담당
Button.OnClickListener listener = new Button.OnClickListener() {
@Override
public void onClick() {
System.out.println("전화를 겁니다.");
}
};
// button2의 클릭 이벤트 처리는 setter 메소드의 매개값으로 준 익명 구현 객체가 담당
Window() {
button1.setOnClickLister(listener); // 매개값으로 필드를 대입
button2.setOnClickLister(new Button.OnClickListener() {
@Override
public void onClick() {
System.out.println("메시지를 보냅니다.");
}
});
}
}
<Main 클래스>
public class Main {
public static void main(String[] args) {
Window window = new Window();
window.button1.touch(); // 전화를 겁니다.
window.button2.touch(); // 메시지를 보냅니다.
}
}
익명 객체의 로컬 변수 사용
- 익명 객체 내부에서 매개변수나 로컬변수를 사용할 때 메소드 실행이 끝나도 지속적으로 사용이 가능하도록 매개변수나 로컬변수를 final로 선언하도록 요구한다.
- 이 경우 final을 생략해도 되는데 그러면 컴파일러가 자동으로 final 특성을 부여해준다.
<익명 객체의 로컬 변수>
interface Calculatable { // 인터페이스 선언
int sum(); // 추상 메소드 선언
}
public class Anonymous {
int field; // 필드 선언 (언제나 수정 가능)
public void method(final int arg1, int arg2) {
// 메소드 내부에서 선언된 매개변수나 로컬 변수들은 모두 수정이 불가능
// 전부 final 특성을 지닌다.
final int var1 = 40;
int var2 = 50;
field = 10;
// arg1 = 20; // final을 붙여도
// arg2 = 20; // final을 안붙여도 둘다 값 수정이 불가능하다.
// var1 = 30; // final을 붙여도
// var2 = 30; // final을 안붙여도 둘다 값 수정이 불가능하다.
// 만약 값 수정을 시도한다면 아래 sum() 메소드 계산 식에서 컴파일 에러 발생함
Calculatable calc = new Calculatable() {
@Override
public int sum() {
int result = field + arg1 + arg2 + var1 + var2;
return result;
}
};
System.out.println(calc.sum());
}
}
public class AnonymousExample {
public static void main(String[] args) {
Anonymous anony = new Anonymous();
anony.method(20, 30); // 10 + 20 + 30 + 40 + 50 = 150
}
}
728x90
'👨🏫Study > JAVA' 카테고리의 다른 글
[JAVA] 10 - 2 예외 처리 (0) | 2022.03.21 |
---|---|
[JAVA] 10 - 1 예외 클래스 (0) | 2022.03.21 |
[JAVA] 09 - 1 중첩 클래스와 중첩 인터페이스 소개 (0) | 2022.03.21 |
[JAVA] 08 - 2 타입 변환과 다형성 (0) | 2022.03.21 |
[JAVA] 08 - 1 인터페이스 (0) | 2022.03.21 |
댓글