What
局部內(nèi)部類就是定義在某個(gè)方法內(nèi)部的內(nèi)部類,它的作用域僅限于這個(gè)方法。
Why
當(dāng)我們在外圍類中定義的內(nèi)部類僅僅在某個(gè)方法中使用了一次,這種情況下,我們就可以選擇去使用局部內(nèi)部類。
How
以上節(jié)課的例子繼續(xù)講解,由于TestListener這個(gè)內(nèi)部類僅僅在start方法中使用了一次,所以我們在這里可以使用局部內(nèi)部類
public?class?InnerClassTest?{????private?Integer?times;????private?boolean?beep;????public?InnerClassTest(Integer?times,?boolean?beep)?{????????this.interval?=?interval;????????this.beep?=?beep;????};????public?void?start(){????????class?TestListener?implements?ActionListner?{????????????public?void?actionPerformed(ActionEvent?event)?{????????????????System.out.println("TestListener?is?running");????????????????if?(beep)?{????????????????????Tookit.getDefaultToolkit().beep();????????????????}????????????}????????}????????ActionListener?listener?=?new?TestListener();????????Timer?t?=?new?Timer(times,?listner);????????t.start();????}????}
這里需要注意,局部類不可以使用public或者private訪問修飾符進(jìn)行聲明,因?yàn)樗饔糜騼H僅被限定在聲明這個(gè)局部類的塊中。
局部類有一個(gè)優(yōu)勢,它可以對外部世界完全的隱藏,即使他的外部類中的其他模塊也不可以訪問它,除了start方法以外,沒有任何方法知道這個(gè)內(nèi)部類的存在。
外部方法訪問變量(進(jìn)階)
與其他的內(nèi)部類相比,局部類還有一個(gè)其他內(nèi)部類所不具備的有優(yōu)點(diǎn)。它不僅可以訪問包含它們的外部類,還可以訪問局部變量,但是這些局部變量必須聲明為final,它們一旦被賦值,就不能被改變。
下面我們接著來改變上面的那個(gè)栗子:
public?void?start(int?times,?boolean?beep){????class?TestListener?implements?ActionListner?{????????public?void?actionPerformed(ActionEvent?event)?{????????????System.out.println("TestListener?is?running");????????????if?(flag)?{????????????????Tookit.getDefaultToolkit().beep();????????????}????????}????}????ActionListener?listener?=?new?TestListener();????Timer?t?=?new?Timer(times,?listner);????t.start();}
我們可以看到,外圍類不在需要去存儲實(shí)例變量beep了,它只是引用start方法中的參數(shù)。
接下來我們來深入了解這個(gè)方法的控制流程:
1.調(diào)用start方法
2.調(diào)用內(nèi)部類的構(gòu)造器,初始化對象變量listener
3.將listener引用傳遞給Timer構(gòu)造器,定時(shí)器開始計(jì)時(shí),start方法結(jié)束。此時(shí),start方法中beep變量被回收。
4.然后actionPerformed方法執(zhí)行if(beep)。
看到這里,我相信大部分人會有疑問,為什么beep變量被回收,但是actionPerformed方法仍然可以調(diào)用到這個(gè)方法?
實(shí)際上,內(nèi)部類在beep域被釋放之前將beep域用start方法中的局部變量進(jìn)行備份,我們接下來來看一下反編譯后的內(nèi)部類,來證實(shí)我們的猜測:
class?InnerClassTest$TestListener?{????public?InnerClass$TestListener(InnerClassTest,?boolean);????public?void?actionPerformed(java.awt.event.ActionEvent);????final?boolean?val$beep;????final?InnerClassTest?this$0;}
請注意構(gòu)造器的boolean參數(shù)和val$beep實(shí)例變量。當(dāng)創(chuàng)建一個(gè)對象的時(shí)候,beep就會傳遞給構(gòu)造器,并存儲在val$beep域中。編譯器必須檢測對局部變量的訪問,為每一個(gè)變量建立相應(yīng)的數(shù)據(jù)域,并將局部變量拷貝到構(gòu)造器中,以便將這些數(shù)據(jù)域初始化為局部變量的副本。
匿名內(nèi)部類
匿名內(nèi)部類其實(shí)就是對局部內(nèi)部類的一個(gè)深化的應(yīng)用,如果我們只是需要?jiǎng)?chuàng)建這個(gè)類的一個(gè)對象,那么我們完全不必去給這個(gè)類命名,這種類就被稱為匿名內(nèi)部類。
接下來,我們接著對上面的例子進(jìn)行改編:
public?void?start(int?times,?boolean?beep){??????ActionListener?listener?=?new?ActionListener()?{????????public?void?actionPerformed(ActionEvent?event)?{????????????System.out.println("TestListener?is?running");????????????if?(flag)?{????????????????Tookit.getDefaultToolkit().beep();????????????}????????}????}????Timer?t?=?new?Timer(times,?listner);????t.start();}
這段語句的含義是:創(chuàng)建一個(gè)實(shí)現(xiàn)ActionListener接口的類的新對象,需要實(shí)現(xiàn)的方法定義在括號內(nèi)。
通用的語法格式是:
new?SuperType(constrution?params)?{????inner?class?methods?and?data}
其中SuperType既可以是接口,那么內(nèi)部類就要去實(shí)現(xiàn)這個(gè)接口,它同樣可以是一個(gè)類,那么內(nèi)部類就要去擴(kuò)展它。
由于構(gòu)造器的名字必須與類名相同,但是匿名類并沒有類名,所以,匿名類不能有構(gòu)造器。取而代之的是,將構(gòu)造器參數(shù)傳遞給父類構(gòu)造器。尤其是在內(nèi)部類實(shí)現(xiàn)接口的時(shí)候,不能有任何構(gòu)造參數(shù)。
如果構(gòu)造參數(shù)的閉小括號后跟的是單引號,那么就是在構(gòu)造一個(gè)類的新對象,如果說構(gòu)造參數(shù)的閉小括號后面跟一個(gè)開大括號,正在定義的就是匿名內(nèi)部類。
靜態(tài)內(nèi)部類(僅供了解)
有時(shí)候,使用內(nèi)部類只是為了把一個(gè)類隱藏在另外一個(gè)類的內(nèi)部,并不需要內(nèi)部類引用外部類對象。所以可以把內(nèi)部類聲明為static,以便取消產(chǎn)生的引用。
只有內(nèi)部類可以聲明為static,靜態(tài)內(nèi)部類的對象除了沒有對生成它的外圍類對象的引用特權(quán)外,與其他所有內(nèi)部類完全一樣。
與常規(guī)內(nèi)部類不同的地方是,靜態(tài)內(nèi)部類可以有靜態(tài)域和方法,聲明在接口中的內(nèi)部類自動生成static和public類。
以上就是長沙一度軟件培訓(xùn)java培訓(xùn)機(jī)構(gòu)的小編針對“Java基礎(chǔ)學(xué)習(xí)系列,局部內(nèi)部類”的內(nèi)容進(jìn)行的回答,希望對大家有所幫助,如有疑問,請?jiān)诰€咨詢,有專業(yè)老師隨時(shí)為你服務(wù)。