익명클래스
이름이 없는 객체 / 클래스
사용하는 이유?
- 프로그램에서 일시적으로 한번만 사용되고 버려지는 객체일 경우
(단발성 이벤트 처리 : 스레드, UI이벤트 처리 등)
- 재사용성이 없을때
매번 클래스를 생성해야하는 비용이 더 많이 들때
상단에 클래스를 정의하는 것보다, 지역변수처럼 익명 클래스로 정의하고 스택이 끝나면 삭제되도록 하는 것이 유지보수면이나 프로그램 메모리면에서 이점을 얻을 수 있다.
구현 방법
- 익명 자식 객체
Coffee라는 부모 클래스 생성
class Coffee {
public void order(String coffee) {
System.out.println("주문하신 " + coffee + " 나왔습니다.");
}
public void returnTray() {
System.out.println("커피 반납이 완료되었습니다.");
}
}
public class Anonymous {
// 1 : 필드에 익명 자식 객체를 생성
// 특정 클래스 내부에서 여러 메소드에 이용될때 고려할만하다.
Coffee specialCoffee1 = new Coffee() { // Coffee라는 객체를 위한 확장 클래스
@Override
public void order(String coffee) {
super.order(coffee);
System.out.println("(귓속말) 딸기 케이크는 서비스예요.");
}
@Override
public void returnTray() {
System.out.println("(귓속말) 자리에 두시면 제가 치울게요.");
}
public void print() {
System.out.println("커피는 맛있습니다");
}
};
specialCoffee1.order("바닐라 라떼");
specialCoffee1.returnTray();
// 2. 로컬 변수의 초기값으로 대입
// 메소드에서 일회용으로 사용하고 버려질 클래스일때
void method2Coffee() {
Coffee specialCoffee2 = new Coffee() {
@Override
public void order(String coffee) {
super.order(coffee);
System.out.println("(귓속말) 딸기 케이크는 서비스예요.");
}
@Override
public void returnTray() {
System.out.println("(귓속말) 자리에 두시면 제가 치울게요.");
}
};
specialCoffee2.order("바닐라 라떼");
specialCoffee2.returnTray();
}
// 3. 익명 객체 매개변수로 대입
// 메소드 매개변수로서 클래스 자료형이 이용된다고 할때, 일회성으로만 사용한다면 아규먼트로 익명객체를 넘겨주면 된다.
void method3Coffee(Coffee coffee) {
coffee.order("바닐라 라떼");
coffee.returnTray();
}
}
public class AnonymousExample {
public static void main(String[] args) {
Anonymous a = new Anonymous();
// 방법 1 : 익명객체 필드 사용
a.specialCoffee1.returnTray();
a.specialCoffee1.print(); // Error !
// 방법 2 : 익명객체 로컬 변수 사용
a.method1Coffee();
// 방법 3 : 매개변수로 익명개체 사용
a.method2Coffee(new Coffee(){
@Override
public void order(String coffee) {
super.order(coffee);
System.out.println("(귓속말) 딸기 케이크는 서비스예요.");
}
@Override
public void returnTray() {
System.out.println("(귓속말) 자리에 두시면 제가 치울게요.");
}
};
}
}
new Coffee() {} 를 통해서 생성하는 인스턴스는 별도의 클래스가 아닌 Coffee 클래스를 상속받는 익명 클래스이기 때문에, 부모인 Coffee 클래스 자체에는 print()메소드가 선언되어 있지 않기에 사용하지 못한다. ( 다형성의 법칙)
새로 정의한 print() 메소드는 외부 스코프에서 호출할 수 없고, 익명클래스 내에서만 호출이 가능하다.
- 익명 구현 객체
인터페이스를 바로 구현해서 구현한 클래스명이 없이 객체를 만드는 것!
익명 클래스를 실무에서 사용하는 일은 극히 드물다고함!
일반 상속 익명 객체와 다른 점은 상속과 다르게 인터페이스는 강제적으로 정의해야하는 메서드가 있기에, 규격화에 도움이 됨
(Runnable, Thread) 선언하는 방법도 이와 비슷한형태임
public class Button {
// 인터페이스 타입 필드
OnClickListener listener;
void setOnClickListener(OnClickListener listener){
this.listener = listener;
}
// 구현 객체의 onClick() 메소드 호츨
void touch() {
listener.onClick();
}
// 중첩 인터페이스
interface OnClickListener{
void onClick();
}
}
public class ButtonHandeler {
Button endButton = new Button();
Button startButton = new Button();
// 클래스 필드 객체 생성과 동시에 익명 구현 객체 할당
Button.OnClickListener listener = new Button.OnClickListener() {
@Override
public void onClick() {
System.out.println("프로그램을 종료합니다.");
}
};
ButtonHandler(){
//위 필드에서 생성한 익명 구현객체로 endButton listener setting
endButton.setOnClickListener(listener);
//startButton listener setting하는 메서드 호출과 동시에 익명 구현객체 정의
startButton.setOnClickListener(new Button.OnClickListener() {
@Override
public void onClick() {
System.out.println("프로그램을 시작합니다.");
}
});
}
}
public class AnonymousExample {
public static void main(String[] args) {
ButtonHandler buttonHandler = new ButtonHandler();
buttonHandler.endButton.touch();
buttonHandler.startButton.touch();
}
}
Comparator 인터페이스를 호출해서 Arrays.sort() 메서드의 매개변수로 나열하는 방법도 있다.
import java.util.Arrays;
import java.util.Comparator; // Comparator 인터페이스 호출
public class Main {
public static void main(String[] args) {
class User {
String name;
int age;
User(String name, int age) {
this.name = name;
this.age = age;
}
}
User[] users = {
new User("홍길동", 32),
new User("김춘추", 64),
new User("임꺽정", 48),
new User("박혁거세", 14),
};
// Arrays.sort(배열, Comparator 익명 구현 객체)
Arrays.sort(users, new Comparator<User>() {
@Override
public int compare(User u1, User u2) {
return Integer.compare(u1.age, u2.age); // Integer 클래스에 정의된 compare 함수로 두 가격 정수 원시값을 비교
}
});
}
}
한계점
익명 구현 객체는 오직 하나의 인터페이스만 구현이 가능하다.
인터페이스는 다중 상속(구현)이 가능하지만, 익명 구현 객체로는 불가능하다
다중 구현한 클래스는 따로 정의하여 사용해야한다.
JAVA
interface IAnimal {
}
interface ICreature {
}
abstract class myClass {
}
public class Main {
public static void main(String[] args) {
class useClass1 implements IAnimal, ICreature {
}
class useClass2 extends myClass implements IAnimal {
}
useClass1 u1 = new useClass1() {
};
useClass2 u2 = new useClass2() {
};
}
}
참조:
https://limkydev.tistory.com/227
'Language > Java' 카테고리의 다른 글
[Java] Hashmap 정렬방법 (0) | 2023.02.01 |
---|---|
[Java] 람다 표현식 / 함수형 인터페이스 (@FunctionalInterface) (0) | 2023.01.31 |
[Java] 오버로딩 & 오버라이딩 Overloading / Overriding (0) | 2023.01.31 |
[ JAVA ] Comparable과 Comparator (0) | 2021.08.06 |
[JAVA/자바] Arrays클래스 : fill, sort, copyOf (0) | 2021.07.12 |