更新時間:2020-08-12 16:17:54 來源:動力節點 瀏覽2106次
What
局部內部類就是定義在某個方法內部的內部類,它的作用域僅限于這個方法。
Why
當我們在外圍類中定義的內部類僅僅在某個方法中使用了一次,這種情況下,我們就可以選擇去使用局部內部類。
How
以上節課的例子繼續講解,由于TestListener這個內部類僅僅在start方法中使用了一次,所以我們在這里可以使用局部內部類
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訪問修飾符進行聲明,因為它作用域僅僅被限定在聲明這個局部類的塊中。
局部類有一個優勢,它可以對外部世界完全的隱藏,即使他的外部類中的其他模塊也不可以訪問它,除了start方法以外,沒有任何方法知道這個內部類的存在。
外部方法訪問變量(進階)
與其他的內部類相比,局部類還有一個其他內部類所不具備的有優點。它不僅可以訪問包含它們的外部類,還可以訪問局部變量,但是這些局部變量必須聲明為final,它們一旦被賦值,就不能被改變。
下面我們接著來改變上面的那個栗子:
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();
}
我們可以看到,外圍類不在需要去存儲實例變量beep了,它只是引用start方法中的參數。
接下來我們來深入了解這個方法的控制流程:
1.調用start方法
2.調用內部類的構造器,初始化對象變量listener
3.將listener引用傳遞給Timer構造器,定時器開始計時,start方法結束。此時,start方法中beep變量被回收。
4.然后actionPerformed方法執行if(beep)。
看到這里,我相信大部分人會有疑問,為什么beep變量被回收,但是actionPerformed方法仍然可以調用到這個方法?
實際上,內部類在beep域被釋放之前將beep域用start方法中的局部變量進行備份,我們接下來來看一下反編譯后的內部類,來證實我們的猜測:
class?InnerClassTest$TestListener?{
????public?InnerClass$TestListener(InnerClassTest,?boolean);
????public?void?actionPerformed(java.awt.event.ActionEvent);
????final?boolean?val$beep;
????final?InnerClassTest?this$0;
}
請注意構造器的boolean參數和val$beep實例變量。當創建一個對象的時候,beep就會傳遞給構造器,并存儲在val$beep域中。編譯器必須檢測對局部變量的訪問,為每一個變量建立相應的數據域,并將局部變量拷貝到構造器中,以便將這些數據域初始化為局部變量的副本。
匿名內部類
匿名內部類其實就是對局部內部類的一個深化的應用,如果我們只是需要創建這個類的一個對象,那么我們完全不必去給這個類命名,這種類就被稱為匿名內部類。
接下來,我們接著對上面的例子進行改編:
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();
}
這段語句的含義是:創建一個實現ActionListener接口的類的新對象,需要實現的方法定義在括號內。
通用的語法格式是:
new?SuperType(constrution?params)?{
????inner?class?methods?and?data
}
其中SuperType既可以是接口,那么內部類就要去實現這個接口,它同樣可以是一個類,那么內部類就要去擴展它。
由于構造器的名字必須與類名相同,但是匿名類并沒有類名,所以,匿名類不能有構造器。取而代之的是,將構造器參數傳遞給父類構造器。尤其是在內部類實現接口的時候,不能有任何構造參數。
如果構造參數的閉小括號后跟的是單引號,那么就是在構造一個類的新對象,如果說構造參數的閉小括號后面跟一個開大括號,正在定義的就是匿名內部類。
靜態內部類(僅供了解)
有時候,使用內部類只是為了把一個類隱藏在另外一個類的內部,并不需要內部類引用外部類對象。所以可以把內部類聲明為static,以便取消產生的引用。
只有內部類可以聲明為static,靜態內部類的對象除了沒有對生成它的外圍類對象的引用特權外,與其他所有內部類完全一樣。
與常規內部類不同的地方是,靜態內部類可以有靜態域和方法,聲明在接口中的內部類自動生成static和public類。
以上就是動力節點java培訓機構的小編針對“Java基礎學習系列,局部內部類”的內容進行的回答,希望對大家有所幫助,如有疑問,請在線咨詢,有專業老師隨時為你服務。
0基礎 0學費 15天面授
有基礎 直達就業
業余時間 高薪轉行
工作1~3年,加薪神器
工作3~5年,晉升架構
提交申請后,顧問老師會電話與您溝通安排學習