java 匿名類(匿名内部類)
1. 初識 匿名類
标準說法: 内部類包括:成員類、局部類、匿名類(匿名内部類)。
匿名類概念:
- 匿名類可以使你的代碼更加簡潔 (JDK8之後Lambda更簡潔)。
- 你可以定義一個類的同時對其進行執行個體化。
- 它與局部類很相似,不同的是它沒有類名,如果某個局部類你隻需要使用一次,就可以使用匿名類代替局部類。
- 匿名類是表達式,而非正常的類
匿名類的使用場景:
- 一個局部類隻需要使用一次的時候
- 由于匿名類沒有類名,那麼除了定義它的地方,其他地方無法調用,是以匿名類也可以叫匿名内部類
2. 通過示例分析局部類和匿名類差別
sayHello
方法中有局部類和匿名類分别實作
HelloWorld
接口的方法
public class HelloWorldAnonymousClasses {
interface HelloWorld {
public void greet();
public void greetSomeone(String someone);
}
public void sayHello() {
/**
* 1、局部類:EnglishGreeting實作了HelloWorld接口
*/
class EnglishGreeting implements HelloWorld {
String name = "無參";
@Override
public void greet() {
greetSomeone(name);
}
@Override
public void greetSomeone(String someone) {
name = someone;
System.out.println("局部類:" + name);
}
}
// 建立局部類EnglishGreeting的執行個體化對象,使用接口類型接收
HelloWorld englishGreeting = new EnglishGreeting();
// 局部類:無參方法
englishGreeting.greet();
// 局部類:帶參方法
englishGreeting.greetSomeone("帶參");
/**
* 2、匿名類實作HelloWorld接口并建立了執行個體化對象:frenchGreeting
*/
HelloWorld frenchGreeting = new HelloWorld() {
String name = "無參";
@Override
public void greet() {
greetSomeone(name);
}
@Override
public void greetSomeone(String someone) {
name = someone;
System.out.println("匿名類:" + name);
}
};
// 匿名類:無參方法
frenchGreeting.greet();
// 匿名類:帶參方法
frenchGreeting.greetSomeone("帶參");
}
public static void main(String... args) {
HelloWorldAnonymousClasses myApp = new HelloWorldAnonymousClasses();
myApp.sayHello();
}
【輸出】
局部類:無參
局部類:帶參
匿名類:無參
匿名類:帶參
【分析】
代碼裡局部類和匿名類實作的功能是一樣的,内部的方法實作的代碼是也一樣的,差別隻在實作
HelloWorld
接口的地方
局部類的格式是:
- 建立局部類并且實作接口:
class EnglishGreeting implements HelloWorld {...}
- 建立局部類的執行個體化對象并用接口類型接收:
HelloWorld englishGreeting = new EnglishGreeting();
- 調用執行個體化對象的方法
匿名類的格式是:
- 建立匿名類實作接口同時對其進行執行個體化:
HelloWorld frenchGreeting = new HelloWorld() {...}
- 調用執行個體化對象的方法
【差別】
- 局部類
實作EnglishGreeting
接口,有自己的類名:HelloWorld
,定義完成後需要再對其執行個體化對象:EnglishGreeting
才能可以使用方法englishGreeting
- 匿名類在定義時就已經執行個體化成對象:
,定義完了就可以直接使用方法frenchGreeting
- 匿名類是一個表達式,是以在定義的最後用分号結束
3. 匿名内部類的文法
3.1 匿名類實作接口
其實上面的示例中的匿名類就是實作接口的方式,這個示例将實作更複雜的功能
public class InterfaceTest {
public static void main(String[] args) {
TomInterface tif = new TomInterface() {
String name = "湯姆";
@Override
public void getName() {
System.out.println(name);
}
TomInterface setName(String name){
this.name = name;
return this;
}
}.setName("傑瑞");
tif.getName();
}
}
interface TomInterface{
void getName();
}
【結果】
傑瑞
【分析】
-
方法建立匿名類實作main
接口并執行個體化:TomInterface
new TomInterface{...}
- 調用匿名類對象的
方法,将setName
指派給匿名類的成員變量傑瑞
,并傳回目前執行個體name
給接口變量this
tif
-
方法調用匿名類對象的方法main
,而此時的匿名類的成員變量tif.getName()
的值已經被替換成name
,是以最後輸出傑瑞
而不是傑瑞
湯姆
3.2 匿名類繼承父類 (匿名子類)
public class ExtendTest {
public static void main(String[] args) {
String name = "李四";
// 建立父類對象,列印原始name值
PartherClass partherClass = new PartherClass();
System.out.println("父類的getName方法=" + partherClass.getName());
// 使用匿名類繼承父類,并列印name值
PartherClass pc = new PartherClass(name){
@Override
public String getName(){
return "匿名類 - "+super.getName();
}
};
System.out.println(pc.getName());
}
}
class PartherClass{
private String name = "張三";
public PartherClass(){}
public PartherClass(String name){
this.name = name;
}
public String getName(){
return this.name;
}
}
父類的getName方法=張三
匿名類 - 李四
- 建立父類對象并調用
方法,這個不用細說getName
- 建立匿名類繼承父類并執行個體化對象:
,本次匿名類調用的是父類的帶參構造,将參數指派給了父類的pc
name
- 調用匿名類重寫的
方法,得到新的getName
值name
3.3 差別
Demo demo = new Demo(xxx){...}
- 操作符:new
- 一個要實作的接口或要繼承的類,示例3.1 是實作接口,示例3.2 是繼承類
- 一對括号,如果是匿名子類,那麼父類有構造參數就填,不帶參就空着;如果匿名類是實作接口,那麼括号裡需要空着
-
,括号裡括着的是匿名類的聲明主體{...}
- 末尾的
号,因為匿名類的聲明是一個表達式,是語句的一部分,是以需要分号結尾;
- 表面上看匿名類沒有類名,沒有構造參數。但其實在編譯的時候,編譯器會給匿名類配置設定類名和構造器,隻是我們無法操作也不能複用。如需驗證,可以看編譯後的class檔案,多出一個命名格式:
的檔案。例如示例3.2,匿名類的class檔案就是:匿名類定義類$?.class
ExtendTest$1.class