자바에서 익명 클래스(anonymous class)는 이름이 없는 내부 클래스로서, 주로 인터페이스나 추상 클래스의 인스턴스를 구현하거나 상속을 받는 데 사용됩니다.
익명 클래스는 클래스 정의와 동시에 인스턴스를 생성하므로 일회성으로 사용되는 간단한 구현이 필요한 경우 유용하게 활용됩니다.
익명 클래스는 다음과 같은 형태로 작성됩니다
인터페이스명 변수명 = new 인터페이스명() {
// 인터페이스의 메서드 구현
// 추가적인 필드나 메서드 정의 가능
};
또는
부모클래스명 변수명 = new 부모클래스명() {
// 부모 클래스의 메서드 오버라이딩
// 추가적인 필드나 메서드 정의 가능
};
여기서 인터페이스명은 구현하고자 하는 인터페이스의 이름이며, 부모클래스명은 상속을 받고자 하는 부모 클래스의 이름입니다.
익명 클래스는 해당 인터페이스나 추상 클래스의 추상 메서드를 구현하거나, 부모 클래스의 메서드를 오버라이딩하여 동작을 재정의할 수 있습니다. 또한 익명 클래스 내부에서 필드와 메서드를 추가로 정의할 수도 있습니다. 익명 클래스의 인스턴스는 해당 인터페이스나 추상 클래스의 타입으로 선언된 변수에 할당되어 사용됩니다.
익명 클래스는 주로 이벤트 리스너, 스레드, 콜백 등 다양한 상황에서 활용됩니다. 예를 들어, 버튼의 클릭 이벤트 처리를 위해 익명 클래스를 사용할 수 있습니다. 익명 클래스를 사용하면 클래스를 명시적으로 정의하지 않고도 간단하게 인터페이스나 추상 클래스를 구현할 수 있어 코드의 가독성과 간결성을 높일 수 있습니다.
public interface Runnable {
/**
* 스레드가 실행할 작업을 정의합니다.
*/
public abstract void run();
}
Runnable 인터페이스는 단 하나의 추상 메서드 run()을 가지고 있습니다. 이 메서드는 스레드가 실행될 때 호출되는 메서드로, 스레드가 수행해야 할 작업을 구현하는 역할을 합니다. run() 메서드는 매개변수도 없고 반환값도 없는 void 타입입니다.
Runnable 인터페이스는 스레드 클래스(Thread)와 함께 사용되어 스레드의 실행 코드를 분리하는데 주로 활용됩니다. Runnable 인터페이스를 구현하는 클래스는 run() 메서드를 오버라이딩하여 스레드가 실행할 작업을 정의하고, 이를 스레드 객체에 전달하여 스레드를 생성하고 실행할 수 있습니다.
Runnable 인터페이스의 사용은 스레드와 작업을 분리함으로써 코드의 가독성과 재사용성을 높이는데 도움을 줍니다. 이를 통해 스레드 클래스와 작업 클래스를 분리함으로써 작업 코드를 다른 스레드에도 쉽게 적용할 수 있고, 더욱 유연하고 확장 가능한 멀티스레드 애플리케이션을 개발할 수 있습니다.
public class Thread implements Runnable {
private volatile ThreadGroup group;
private Runnable target; // interface를 queue에 쌓아 놓고 씀.
private String name;
private long stackSize;
// ...
public Thread() {
init(null, null, "Thread-" + nextThreadNum(), 0);
}
public Thread(Runnable target) { //Runnable이라는 interface를 전달. //Anonymous로 구현
init(null, target, "Thread-" + nextThreadNum(), 0);
}
public Thread(ThreadGroup group, Runnable target, String name, long stackSize) {
init(group, target, name, stackSize);
}
private void init(ThreadGroup group, Runnable target, String name, long stackSize) {
// ...
}
public synchronized void start() {
// ...
}
public void run() {
if (target != null) {
target.run();
}
}
// ...
}
다음은 익명 클래스를 사용하여 인터페이스를 구현하는 예제 코드입니다. 이 예제에서는 Runnable 인터페이스를 구현하는 익명 클래스를 사용하여 스레드를 생성하고 실행하는 방법을 보여줍니다.
public class AnonymousClassExample {
public static void main(String[] args) {
// 익명 클래스를 사용하여 Runnable 인터페이스 구현
Runnable runnable = new Runnable() { /Anonymous Class
@Override
public void run() {
System.out.println("Hello, World!"); // 이 코드가 실행되면 끝.
}
};
// 익명 클래스를 사용한 스레드 생성
Thread thread = new Thread(runnable);
// 스레드 실행
thread.start();
}
}
다음은 추상 클래스의 인스턴스를 구현하는 익명 클래스를 사용한 예제 코드입니다. 이 예제에서는 추상 클래스 Animal을 상속받아 익명 클래스를 구현하고, 해당 익명 클래스의 인스턴스를 생성하여 동작을 확인합니다.
abstract class Animal {
abstract void makeSound();
}
public class AnonymousClassExample {
public static void main(String[] args) {
// 추상 클래스를 구현한 익명 클래스
Animal animal = new Animal() {
@Override
void makeSound() {
System.out.println("멍멍!");
}
};
// 익명 클래스의 메서드 호출
animal.makeSound();
}
}
위의 코드에서 Animal 추상 클래스를 상속받아 익명 클래스를 생성하고, makeSound() 메서드를 오버라이딩하여 "멍멍!"이라는 문자열을 출력하도록 구현했습니다. 그리고 익명 클래스의 인스턴스를 생성하여 animal 변수에 할당합니다.
animal 변수의 makeSound() 메서드를 호출하면 익명 클래스에서 재정의한 메서드가 실행되어 "멍멍!"이라는 결과가 출력됩니다.
이 예제에서는 추상 클래스를 인스턴스화하기 위해 익명 클래스를 사용했지만, 이와 비슷한 방식으로 인터페이스를 구현하는 익명 클래스를 만들 수도 있습니다.
다음은 추가적인 필드와 메서드를 포함한 익명 클래스를 사용한 예제 코드입니다. 이 예제에서는 추상 클래스 Animal을 상속받아 익명 클래스를 구현하고, 필드와 메서드를 추가하여 동작을 확인합니다.
abstract class Animal {
abstract void makeSound();
}
public class AnonymousClassExample {
public static void main(String[] args) {
// 추상 클래스를 구현한 익명 클래스
Animal animal = new Animal() {
private String name = "Dog";
@Override
void makeSound() {
System.out.println(name + " is barking!");
}
void wagTail() {
System.out.println(name + " is wagging its tail.");
}
};
// 익명 클래스의 메서드 호출
animal.makeSound();
// 추가적인 메서드 호출
if (animal instanceof Dog) {
Dog dog = (Dog) animal;
dog.wagTail();
}
}
// 익명 클래스에서 추가적인 메서드를 사용하기 위해 타입 캐스팅을 위한 하위 클래스 생성
static class Dog extends Animal {
@Override
void makeSound() {
// 구현하지 않음
}
}
}
위의 코드에서 익명 클래스는 name이라는 private 필드와 wagTail()이라는 추가적인 메서드를 가지고 있습니다. makeSound() 메서드를 오버라이딩하여 Dog is barking!이라는 결과를 출력하도록 구현했습니다.
Animal 변수인 animal의 makeSound() 메서드를 호출하면 익명 클래스에서 재정의한 메서드가 실행되어 Dog is barking!이라는 결과가 출력됩니다. 또한 animal 변수를 Dog 타입으로 타입 캐스팅한 후 wagTail() 메서드를 호출하여 Dog is wagging its tail.이라는 결과를 출력합니다.
위의 코드에서는 익명 클래스에서 추가적인 메서드를 사용하기 위해 Dog라는 하위 클래스를 생성하여 타입 캐스팅을 수행하였습니다. 이를 통해 익명 클래스에 추가한 메서드를 활용할 수 있습니다.