이름이 없는 객체를 익명객체라 한다. 명시적으로 클래스를 선언하지 않기 때문에 쉽게 객체를 생성할 수 있다.
익명객체는 필드값, 로컬 변수값, 매개변수값으로 주로 사용된다.
익명 객체는 클래스를 상속하고나 인터페이스를 구현해야만 생성할 수 있다.
상속시에 익명 상속 객체, 구현시에 익명 구현 객체라고 한다.
익명 자식객체
new 부모생성자(매개값) {
//필드
//메소드
}
익명 자식 객체는 위와 같이 생성된다. 생성된 객체는 부모타입의 필드, 로컬변수, 매개변수 값으로 대입할 수 있다.
블록 안은 익명 자식 객체가 가져야 할 멤버이다. 부모타입의 멤버만 접근할 수 있기때문에 오버라이딩되는 코드가 작성된다.
package ch09.sec07.ex01;
public class Car {
// 필드에 Tire 객체 대입
private Tire tire1 = new Tire();
//필드에 익명 자식객체 대입
private Tire tire2 = new Tire() {
@Override
public void roll() {
System.out.println("익명 자식 Tire 객체 1이 굴러갑니다.");
}
};
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();
}
}
중첩인터페이스도 위와 같지만 추상메서드가 오버라이딩 된다.
package ch09.sec07.ex03;
public class ButtonEx {
public static void main(String[] args) {
Button btnOk = new Button();
btnOk.setClickListener(new Button.ClickListener() {
@Override
public void onClick() {
System.out.println("OK 버튼을 클릭했습니다.");
}
});
btnOk.click();
//--------------------------------------------------------------//
Button btnCancel = new Button();
class CancelListener implements Button.ClickListener {
@Override
public void onClick() {
System.out.println("cancel button 클릭");
}
}
btnCancel.setClickListener(new CancelListener());
btnCancel.click();
}
}
이전 중첩클래스의 Button 예제를 익명객체를 사용하여 리팩터링 한 코드이다. Ok와 Cancel을 비교해서 비교해보자
확인문제 오답노트
package ch09.sec07.ex;
public class Chatting {
class Chat {
void start() {
}
void sendMessage(String message) {
}
}
void startChat(String chatId) {
String nickName = null;
nickName = chatId;
Chat chat = new Chat() {
@Override
public void start() {
while (true) {
String inputData = "안녕하세요";
String message = "[" + nickName + "] " + inputData;
sendMessage(message);
}
}
};
chat.start();
}
}
위 코드에서 컴파일에러가 나는 이유는 익명 객체에서 로컬 변수 nickName이 사용되기 때문이다.
nickName은 사실상 final 이 됨
익명 클래스의 인스턴스가 생성될 때 로컬 변수는 스택프레임에 존재하게 되고, 익명객체의 인스턴스는 힙에 할당되는데
메소드가 종료되면 스택 프레임이 사라지므로 익명 클래스에서 참조되는 로컬 변수를 참조하려면 변수가 변경되지 않아야 함
위 코드에서는 nickName 변수는 null로 초기화되고, chatId로 할당된 후로 값이 변경되지 않았기 때문에 final로 간주되는 것
따라서
package ch09.sec07.ex;
public class Chatting {
class Chat {
void start() {
}
void sendMessage(String message) {
}
}
void startChat(String chatId) {
final String nickName = chatId; // 명시적으로 final 키워드 추가
Chat chat = new Chat() {
@Override
public void start() {
while (true) {
String inputData = "안녕하세요";
String message = "[" + nickName + "] " + inputData;
sendMessage(message);
}
}
};
chat.start();
}
}
명시적으로 final 키워드를 추가했고, 불필요한 초기화를 제거함 (null로 초기화 했던 부분)
'Java' 카테고리의 다른 글
Object 클래스 / HashCode (0) | 2024.07.09 |
---|---|
예외 (1) | 2024.07.09 |
중첩 인터페이스 (0) | 2024.07.06 |
로컬 클래스 / 바깥 클래스 (0) | 2024.07.06 |
중첩 클래스 / 인스턴스 멤버 클래스 / 정적 멤버 클래스 (0) | 2024.07.05 |