Java 匿名類別 (Anonymous Class)
匿名類別是沒有名稱的內部類別,用於建立一次性使用的類別實例,常用於實作介面或繼承類別。
基本語法
// 實作介面的匿名類別
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("執行中");
}
};
// 繼承類別的匿名類別
Thread thread = new Thread() {
@Override
public void run() {
System.out.println("執行緒執行中");
}
};
實作介面
interface Greeting {
void sayHello(String name);
}
// 使用匿名類別
Greeting greeting = new Greeting() {
@Override
public void sayHello(String name) {
System.out.println("Hello, " + name + "!");
}
};
greeting.sayHello("Alice"); // Hello, Alice!
繼承抽象類別
abstract class Animal {
abstract void makeSound();
void sleep() {
System.out.println("睡覺中...");
}
}
Animal dog = new Animal() {
@Override
void makeSound() {
System.out.println("汪汪!");
}
};
dog.makeSound(); // 汪汪!
dog.sleep(); // 睡覺中...
存取外部變數
public void process() {
final String message = "Hello"; // 必須是 final 或 effectively final
int count = 10; // effectively final
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println(message);
System.out.println(count);
// count++; // 錯誤!不能修改
}
};
}
帶建構子參數
abstract class Person {
String name;
Person(String name) {
this.name = name;
}
abstract void introduce();
}
Person person = new Person("Alice") {
@Override
void introduce() {
System.out.println("我是 " + name);
}
};
常見用途
事件處理
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("按鈕被點擊");
}
});
Comparator
List<String> list = Arrays.asList("banana", "apple", "cherry");
Collections.sort(list, new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return s1.length() - s2.length();
}
});
執行緒
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("執行緒執行中");
}
}).start();
匿名類別 vs Lambda
Java 8 後,單一抽象方法的介面可以用 Lambda 取代:
// 匿名類別
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("Hello");
}
};
// Lambda(更簡潔)
Runnable r2 = () -> System.out.println("Hello");
// Comparator
Comparator<String> c1 = new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return s1.compareTo(s2);
}
};
Comparator<String> c2 = (s1, s2) -> s1.compareTo(s2);
Comparator<String> c3 = String::compareTo;
何時使用匿名類別
使用匿名類別:
- 需要多個方法
- 需要存取
this(指向匿名類別本身) - 需要繼承類別
使用 Lambda:
- 單一抽象方法的介面
- 簡短的實作
// 匿名類別的 this
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println(this.getClass()); // 匿名類別
}
};
// Lambda 的 this
Runnable r2 = () -> {
System.out.println(this.getClass()); // 外圍類別
};
重點整理
- 匿名類別沒有名稱,建立時同時定義和實例化
- 可以實作介面或繼承類別
- 只能存取 final 或 effectively final 的外部變數
- 單一抽象方法介面建議用 Lambda 取代
- 匿名類別中的
this指向匿名類別本身