詳解Java內(nèi)部類——匿名內(nèi)部類
今天來看看另一個更加神奇的類——匿名內(nèi)部類。
就像它的名字表示的那樣,這個類是匿名的,用完之后,深藏功與名,就像掃地僧那樣默默潛藏于深山之中。匿名內(nèi)部類不僅沒有名字,連class關(guān)鍵字都省掉了,而且匿名內(nèi)部類必須繼承于某個類或者實(shí)現(xiàn)某個接口,長的就像這樣:
new 父類(參數(shù)列表)|實(shí)現(xiàn)接口() { //匿名內(nèi)部類的內(nèi)部定義 }
來看一個栗子:
public abstract class Human { public abstract void walk();}
這是一個抽象類,如果使用匿名內(nè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(); }}
簡單粗暴,看起來就像局部內(nèi)部類的簡化版。如果不使用匿名內(nèi)部類,會是怎樣呢?
我們需要先創(chuàng)建一個類來繼承這抽象類:
public class Man extends Human { @Override public void walk() { System.out.println('Man can walk.'); }}
然后再來使用這個類:
public class AnonymousTest { public static void main(String[] args) { Human human = new Man(); human.walk(); }}
因?yàn)橐粋€單獨(dú)的類往往放在一個單獨(dú)的文件中,如果這個類只需要創(chuàng)建一個對象,那未免有些大材小用了,從上面的栗子可以比較出匿名內(nèi)部類的一個優(yōu)勢:在類只需要創(chuàng)建一個對象的情況下更加簡單方便。
再舉一個實(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)建了一個繼承于Thread的匿名內(nèi)部類,覆蓋了其中的 run方法,并創(chuàng)建了一個實(shí)例返回給了t,然后再調(diào)用run方法,可以看到,匿名內(nèi)部類只能存在一個實(shí)例對象,因?yàn)閚ew過一次就無法再創(chuàng)建了,也許會覺得局部內(nèi)部類已經(jīng)很局限了,為什么要出現(xiàn)比局部內(nèi)部類適用范圍更小的匿名內(nèi)部類?、
這你就不懂了吧,在Java的實(shí)際使用中,匿名內(nèi)部類大有用處,為什么要使用匿名內(nèi)部類呢?
有時候,我們創(chuàng)建的類只需要一個實(shí)例,比如說在多線程中,要使用多線程,一般先繼承Thread類或者實(shí)現(xiàn)Runnable接口,然后再去調(diào)用它的方法,而每個任務(wù)一般都不一樣,每次都新建一個類顯然會很難管理,因?yàn)槊總€類只用一次就丟掉了,這個時候使用匿名內(nèi)部類就很方便了,不僅不需要管理一堆一次性類,而且創(chuàng)建起來簡單粗暴。就像上述栗子,還能簡化成這樣:
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方法,簡單粗暴。
匿名內(nèi)部類不僅可以繼承于類,也可以實(shí)現(xiàn)于接口,比如說這樣:
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)部類的情況,類只能繼承于一個類,如果一個類需要使用到另一個包中的另一個類的一個protected方法,卻已經(jīng)繼承于另一個類,那么這個時候就不得不用內(nèi)部類來解決了。
比如說,還有一個Woman(女人)類:
public class Woman { protected void dance(){ System.out.println('Woman can dance.'); }}
這個時候,如果Man(男人)也難不住寂寞,想要dance(跳舞)一下,那該怎么辦呢?繼承Woman類?顯然不合乎邏輯,而且也無法實(shí)現(xiàn),因?yàn)橐呀?jīng)繼承于Human類了,但就是想要dance,該怎么辦?
內(nèi)部類的出現(xià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)部類來繼承,從而調(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)部類必須是繼承一個類或者實(shí)現(xiàn)一個接口,但是兩者不可兼得,同時也只能繼承一個類或者實(shí)現(xiàn)一個接口。
2、匿名內(nèi)部類不能定義構(gòu)造函數(shù)。
3、匿名內(nèi)部類中不能存在任何的靜態(tài)成員變量和靜態(tài)方法。
4、匿名內(nèi)部類是特殊的局部內(nèi)部類,所以局部內(nèi)部類的所有限制同樣對匿名內(nèi)部類生效。
5、匿名內(nèi)部類不能是抽象的,它必須要實(shí)現(xiàn)繼承的類或者實(shí)現(xiàn)的接口的所有抽象方法。
那么問題來了,怎樣初始化一個匿名內(nèi)部類呢?畢竟匿名內(nèi)部類是不能有構(gòu)造器的。
當(dāng)然,首先,還是可以使用初始化塊來實(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(); }}
但是這樣顯然就比較呆板,不夠靈活,無法接受外部參數(shù),那么怎樣靈活使用呢?不要心急,方法總比問題多,還是有辦法解決的:
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.'); } }; }}
這里利用初始化塊來對匿名內(nèi)部類進(jìn)行初始化,注意,如果匿名內(nèi)部類需要使用外部的參數(shù)或者變量,那么必須使用final修飾,因?yàn)閮?nèi)部類使用的其實(shí)是參數(shù)的拷貝,并不是參數(shù)本身,為了更明顯的表明參數(shù)不可變,編譯器會要求使用final關(guān)鍵字來修飾需要使用的變量。
至此,匿名內(nèi)部類講解完畢,歡迎大家繼續(xù)關(guān)注!
以上就是詳解Java內(nèi)部類——匿名內(nèi)部類的詳細(xì)內(nèi)容,更多關(guān)于Java 匿名內(nèi)部類的資料請關(guān)注好吧啦網(wǎng)其它相關(guān)文章!
相關(guān)文章:
1. django queryset相加和篩選教程2. 利用ajax+php實(shí)現(xiàn)商品價格計(jì)算3. Java實(shí)現(xiàn)的迷宮游戲4. idea設(shè)置提示不區(qū)分大小寫的方法5. JS圖片懶加載庫VueLazyLoad詳解6. Java利用TCP協(xié)議實(shí)現(xiàn)客戶端與服務(wù)器通信(附通信源碼)7. 使用AJAX(包含正則表達(dá)式)驗(yàn)證用戶登錄的步驟8. Java PreparedStatement用法詳解9. Spring如何集成ibatis項(xiàng)目并實(shí)現(xiàn)dao層基類封裝10. IDEA 2020.1.2 安裝教程附破解教程詳解

網(wǎng)公網(wǎng)安備