詳解Java內(nèi)部類——匿名內(nèi)部類
今天來(lái)看看另一個(gè)更加神奇的類——匿名內(nèi)部類。
就像它的名字表示的那樣,這個(gè)類是匿名的,用完之后,深藏功與名,就像掃地僧那樣默默潛藏于深山之中。匿名內(nèi)部類不僅沒(méi)有名字,連class關(guān)鍵字都省掉了,而且匿名內(nèi)部類必須繼承于某個(gè)類或者實(shí)現(xiàn)某個(gè)接口,長(zhǎng)的就像這樣:
new 父類(參數(shù)列表)|實(shí)現(xiàn)接口() {
//匿名內(nèi)部類的內(nèi)部定義
}
來(lái)看一個(gè)栗子:
public abstract class Human {
public abstract void walk();
}
這是一個(gè)抽象類,如果使用匿名內(nèi)部類來(lái)繼承的話是這樣的:
public class AnonymousTest {
public static void main(String[] args) {
Human human = new Human(){
public void walk(){
System.out.println("AnonymousHuman can walk.");
};
};
human.walk();
}
}
簡(jiǎn)單粗暴,看起來(lái)就像局部?jī)?nèi)部類的簡(jiǎn)化版。如果不使用匿名內(nèi)部類,會(huì)是怎樣呢?
我們需要先創(chuàng)建一個(gè)類來(lái)繼承這抽象類:
public class Man extends Human {
@Override
public void walk() {
System.out.println("Man can walk.");
}
}
然后再來(lái)使用這個(gè)類:
public class AnonymousTest {
public static void main(String[] args) {
Human human = new Man();
human.walk();
}
}
因?yàn)橐粋€(gè)單獨(dú)的類往往放在一個(gè)單獨(dú)的文件中,如果這個(gè)類只需要?jiǎng)?chuàng)建一個(gè)對(duì)象,那未免有些大材小用了,從上面的栗子可以比較出匿名內(nèi)部類的一個(gè)優(yōu)勢(shì):在類只需要?jiǎng)?chuàng)建一個(gè)對(duì)象的情況下更加簡(jiǎn)單方便。
再舉一個(gè)實(shí)際一點(diǎn)的栗子:
public class AnonymousTest {
public static void main(String[] args) {
Thread t = new Thread() {
public void run() {
for (int i = 0; i < 10; i++) {
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i);
}
}
};
t.start();
}
}
這里創(chuàng)建了一個(gè)繼承于Thread的匿名內(nèi)部類,覆蓋了其中的 run方法,并創(chuàng)建了一個(gè)實(shí)例返回給了t,然后再調(diào)用run方法,可以看到,匿名內(nèi)部類只能存在一個(gè)實(shí)例對(duì)象,因?yàn)閚ew過(guò)一次就無(wú)法再創(chuàng)建了,也許會(huì)覺(jué)得局部?jī)?nèi)部類已經(jīng)很局限了,為什么要出現(xiàn)比局部?jī)?nèi)部類適用范圍更小的匿名內(nèi)部類?、
這你就不懂了吧,在Java的實(shí)際使用中,匿名內(nèi)部類大有用處,為什么要使用匿名內(nèi)部類呢?
有時(shí)候,我們創(chuàng)建的類只需要一個(gè)實(shí)例,比如說(shuō)在多線程中,要使用多線程,一般先繼承Thread類或者實(shí)現(xiàn)Runnable接口,然后再去調(diào)用它的方法,而每個(gè)任務(wù)一般都不一樣,每次都新建一個(gè)類顯然會(huì)很難管理,因?yàn)槊總€(gè)類只用一次就丟掉了,這個(gè)時(shí)候使用匿名內(nèi)部類就很方便了,不僅不需要管理一堆一次性類,而且創(chuàng)建起來(lái)簡(jiǎn)單粗暴。就像上述栗子,還能簡(jiǎn)化成這樣:
public class AnonymousTest {
public static void main(String[] args) {
new Thread() {
public void run() {
for (int i = 0; i < 10; i++) {
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i);
}
}
}.start();
}
}
創(chuàng)建實(shí)例后直接調(diào)用run方法,簡(jiǎn)單粗暴。
匿名內(nèi)部類不僅可以繼承于類,也可以實(shí)現(xiàn)于接口,比如說(shuō)這樣:
public class AnonymousTest {
public static void main(String[] args) {
new Thread(new Runnable() {
public void run() {
for (int i = 0; i < 10; i++) {
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i);
}
}
}).start();
}
}
當(dāng)然,還有些不得不用內(nèi)部類的情況,類只能繼承于一個(gè)類,如果一個(gè)類需要使用到另一個(gè)包中的另一個(gè)類的一個(gè)protected方法,卻已經(jīng)繼承于另一個(gè)類,那么這個(gè)時(shí)候就不得不用內(nèi)部類來(lái)解決了。
比如說(shuō),還有一個(gè)Woman(女人)類:
public class Woman {
protected void dance(){
System.out.println("Woman can dance.");
}
}
這個(gè)時(shí)候,如果Man(男人)也難不住寂寞,想要dance(跳舞)一下,那該怎么辦呢?繼承Woman類?顯然不合乎邏輯,而且也無(wú)法實(shí)現(xiàn),因?yàn)橐呀?jīng)繼承于Human類了,但就是想要dance,該怎么辦?
內(nèi)部類的出現(xiàn)讓這個(gè)問(wèn)題變得很簡(jiǎn)單:
public class Man extends Human {
@Override
public void walk() {
System.out.println("Man can walk.");
}
public void dance(){
new Woman(){
public void manDance(){
super.dance();
}
}.manDance();
}
}
因?yàn)樵诓煌陌拢荒苤苯邮褂肳oman的dance方法,但是可以用內(nèi)部類來(lái)繼承,從而調(diào)用protected方法,然后再放入Man的方法中,這樣,Man也能像Woman一樣dance了:
public class AnonymousTest {
public static void main(String[] args) {
Man human = new Man();
human.walk();
human.dance();
}
}
當(dāng)然,使用匿名內(nèi)部類還是有很多限制的:
1、匿名內(nèi)部類必須是繼承一個(gè)類或者實(shí)現(xiàn)一個(gè)接口,但是兩者不可兼得,同時(shí)也只能繼承一個(gè)類或者實(shí)現(xiàn)一個(gè)接口。
2、匿名內(nèi)部類不能定義構(gòu)造函數(shù)。
3、匿名內(nèi)部類中不能存在任何的靜態(tài)成員變量和靜態(tài)方法。
4、匿名內(nèi)部類是特殊的局部?jī)?nèi)部類,所以局部?jī)?nèi)部類的所有限制同樣對(duì)匿名內(nèi)部類生效。
5、匿名內(nèi)部類不能是抽象的,它必須要實(shí)現(xiàn)繼承的類或者實(shí)現(xiàn)的接口的所有抽象方法。
那么問(wèn)題來(lái)了,怎樣初始化一個(gè)匿名內(nèi)部類呢?畢竟匿名內(nèi)部類是不能有構(gòu)造器的。
當(dāng)然,首先,還是可以使用初始化塊來(lái)實(shí)現(xiàn)的,就像這樣:
public class AnonymousTest {
public static void main(String[] args) {
Human human = new Human() {
private String name;
{
name = "human";
}
@Override
public void walk() {
System.out.println(name + " walk.");
}
};
human.walk();
}
}
但是這樣顯然就比較呆板,不夠靈活,無(wú)法接受外部參數(shù),那么怎樣靈活使用呢?不要心急,方法總比問(wèn)題多,還是有辦法解決的:
public class AnonymousTest {
public static void main(String[] args) {
Human human = new AnonymousTest().getHumanInstance("Frank");
human.walk();
}
public Human getHumanInstance(final String name){
return new Human() {
private String nameA;
{
nameA = name;
}
@Override
public void walk() {
System.out.println(nameA + " walk.");
}
};
}
}
這里利用初始化塊來(lái)對(duì)匿名內(nèi)部類進(jìn)行初始化,注意,如果匿名內(nèi)部類需要使用外部的參數(shù)或者變量,那么必須使用final修飾,因?yàn)閮?nèi)部類使用的其實(shí)是參數(shù)的拷貝,并不是參數(shù)本身,為了更明顯的表明參數(shù)不可變,編譯器會(huì)要求使用final關(guān)鍵字來(lái)修飾需要使用的變量。
至此,匿名內(nèi)部類講解完畢,歡迎大家繼續(xù)關(guān)注!
以上就是詳解Java內(nèi)部類——匿名內(nèi)部類的詳細(xì)內(nèi)容,更多關(guān)于Java 匿名內(nèi)部類的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
如何使用MybatisPlus快速進(jìn)行增刪改查詳解
增刪改查在日常開發(fā)中是再正常不多的一個(gè)需求了,下面這篇文章主要給大家介紹了關(guān)于如何使用MybatisPlus快速進(jìn)行增刪改查的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-08-08
Java動(dòng)態(tài)腳本Groovy獲取Bean技巧
這篇文章主要給大家分享的是Java動(dòng)態(tài)腳本Groovy獲取Bean技巧,在Java代碼中當(dāng)我們需要一個(gè)Bean對(duì)象,通常會(huì)使用spring中@Autowired注解,用來(lái)自動(dòng)裝配對(duì)象。下面我們一起進(jìn)入文章學(xué)習(xí)個(gè)表格多 詳細(xì)內(nèi)容吧2021-12-12
使用Java Servlet生成動(dòng)態(tài)二維碼的實(shí)現(xiàn)步驟
在現(xiàn)代互聯(lián)網(wǎng)時(shí)代,二維碼廣泛應(yīng)用于各個(gè)領(lǐng)域,包括支付、認(rèn)證、信息傳遞等,在Web開發(fā)中,通過(guò)Java Servlet生成動(dòng)態(tài)二維碼是一個(gè)常見(jiàn)的需求,本文將介紹如何使用Java Servlet結(jié)合Google的ZXing庫(kù)生成動(dòng)態(tài)二維碼,需要的朋友可以參考下2023-11-11
Java面試題沖刺第十三天--數(shù)據(jù)庫(kù)(3)
這篇文章主要為大家分享了最有價(jià)值的三道數(shù)據(jù)庫(kù)面試題,涵蓋內(nèi)容全面,包括數(shù)據(jù)結(jié)構(gòu)和算法相關(guān)的題目、經(jīng)典面試編程題等,感興趣的小伙伴們可以參考一下2021-07-07
SpringBoot整合redis實(shí)現(xiàn)輸入密碼錯(cuò)誤限制登錄功能
遇到這樣的需求需要實(shí)現(xiàn)一個(gè)登錄功能,并且2分鐘之內(nèi)只能輸入5次錯(cuò)誤密碼,若輸入五次之后還沒(méi)有輸入正確密碼,系統(tǒng)將會(huì)將該賬號(hào)鎖定1小時(shí),這篇文章主要介紹了SpringBoot整合redis并實(shí)現(xiàn)輸入密碼錯(cuò)誤限制登錄功能,需要的朋友可以參考下2024-02-02
Java實(shí)現(xiàn)合并多個(gè)PDF的示例代碼
這篇文章主要介紹了通過(guò)Java實(shí)現(xiàn)合并多個(gè)PDF,并將合并后的新PDF存儲(chǔ)到文件夾下,文中的示例代碼簡(jiǎn)潔易懂,感興趣的可以跟隨小編一起試一試2022-01-01
利用Java如何獲取Mybatis動(dòng)態(tài)生成的sql接口實(shí)現(xiàn)
MyBatis 的強(qiáng)大特性之一便是它的動(dòng)態(tài)SQL,下面這篇文章主要給大家介紹了關(guān)于利用Java如何獲取Mybatis動(dòng)態(tài)生成的sql接口實(shí)現(xiàn)的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-01-01
解決java.lang.ClassCastException的java類型轉(zhuǎn)換異常的問(wèn)題
這篇文章主要介紹了解決java.lang.ClassCastException的java類型轉(zhuǎn)換異常的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-09-09

