內部類
Java 類中的可以定義的成員有:字段、方法、內部類,內部類是定義在類結構中的另一個類,因為定義在類的內部,故稱為內部類。
<code>public class OuterClass {
\t......
\t\t
\tpublic class InnerClass {
\t\t......
\t}
}/<code>
在上述的代碼示例中,就可以將InnerClass稱之為OuterClass的內部類。
為什麼使用內部類:
- 增強面向對象的封裝,可以把一些不想對外的實現細節封裝在內部類中,從而隱藏在外部類之內,限制了其他對象的直接訪問。
- 內部類能提高代碼的可讀性和可維護性。
- 內部類可以直接訪問外部類的成員。
在Java中的LinkedList的源碼中,使用一個內部類Node來封裝鏈表列表中的每一個節點,在節點中存儲了當前節點的值,上一個節點,下一個節點這些信息;而這些信息是不能外部對象直接讀取和使用的,因此,使用內部類封裝隱藏是一個不錯的選擇。
內部類的分類:內部類根據使用的修飾符的不同,或者定義的位置的不同,分成四種類型;
- 實例內部類:內部類沒有使用static修飾,也就是非靜態內部類,定義在類中,方法之外;
- 靜態內部類:內部類使用了static修飾,定義在類中,方法之外,並且使用static修飾;
- 局部內部類:在方法中定義的內部類;
- 匿名內部類:匿名內部類屬於局部內部類的特殊情況,適合於僅使用一次使用的類;
對於每個內部類來說,經過JVM編譯後都會生成獨立的.class字節碼文件,因為JVM會為每一個類產生各自的字節碼文件。
- 成員內部類:外部類名$內部類名字
- 局部內部類:外部類名$數字內部類名稱
- 匿名內部類:外部類名$數字
內部類其實就是外部類的一個成員,跟字段、方法一樣的存在,那麼內部類可以使用訪問控制修飾符:public/缺省/protected/private和static修飾符修飾。
實例內部類
實例內部類:沒有使用static修飾的內部類,實例內部類屬於外部類的對象,不屬於外部類本身;可以通過外部類對象來訪問。其特點是:
1.在實例化內部類之前,必須存在外部類對象,因為要通過外部類對象創建內部類對象,所以存在內部類對象時,一定存在外部類對象;
<code>OutterClass.InnerClass in = new OutterClass().new InnerClass();/<code>
2.實例內部類的實例自動持有外部類的實例的引用,所以內部類可以直接訪問外部類成員;
3.外部類中不能直接訪問內部類的成員,必須通過內部類的實例去訪問;
4.實例內部類中不能定義靜態成員,只能定義實例成員(非靜態成員);
5.如果實例內部類和外部類存在同名的字段或方法abc,那麼在內部類中:
- this.abc:表示訪問內部類成員;
- 外部類.this.abc:表示訪問外部類成員;
實例內部類代碼案例如下:
<code>public class OuterClass {
\t// 外部類成員
\tString name = "Outer.name";
\t
\tpublic void printInnterName() {
\t\t// 訪問內部類成員
\t\tSystem.out.println(this.new InnerClass().name);
\t}
\t\t
\tpublic class InnerClass {
\t\tString name = "InnerClass.name";
\t\t
\t\tpublic void printName() {
\t\t\tString name = "name";
\t\t\t
\t\t\tSystem.out.println(name);
\t\t\tSystem.out.println(this.name);
\t\t\tSystem.out.println(OuterClass.this.name);
\t\t}
\t}
}/<code>
靜態內部類
靜態內部類:使用static修飾的內部類,這點有別於實例內部類,需要特別注意。其特點是:
1.靜態內部類的實例不會自動持有外部類的特定實例的引用,因此在創建內部類的實例時,不必創建外部類的實例。
<code>OutterClass.InnerClass in = new OutterClass.InnerClass();/<code>
2.靜態內部類可以直接訪問外部類的靜態成員,如果要訪問外部類的實例成員,還是必須通過外部類的實例去訪問。
3.在靜態內部類中可以同時定義靜態成員和實例成員。
4.外部類可以通過完整的類名直接訪問靜態內部類的靜態成員。
靜態內部類代碼案例如下:
<code>public class OuterClass {
\t// 外部類成員
\tString name = "Outer.name";
\t// 外部類靜態成員
\tstatic String name2 = "Outer.name2";
\t\t
\tpublic static class InnerClass {
\t\t
\t\tpublic void printName() {
\t\t\tSystem.out.println(name2);
\t\t\tSystem.out.println(new OuterClass().name);
\t\t}
\t}
}/<code>
局部內部類
局部內部類:在方法中定義的內部類,其作用域範圍和當前方法及其當前方法的局部變量是同一個級別。不過局部內部類使用的較少,在開發中也不推薦使用。
- 不能使用public、private、protected、static等這些修飾符;
- 局部內部類只能在當前方法中使用,作用域範圍僅限於當前的方法中;
- 局部內部類和實例內部類一樣,不能擁有靜態成員,但都可以訪問外部類的所有成員;
- 局部內部類訪問的局部變量必須使用final修飾,在Java8中是自動隱式加上final,但是依然是常量,值不能被改變;
為什麼不推薦使用局部內部類?因為如果當前方法不是main方法,那麼當前方法調用完畢之後,當前方法的棧幀會被銷燬,方法內部的局部變量的空間也會全部銷燬。
然而局部內部類是定義在方法中的,在方法中會創建局部內部類對象,局部內部類對象會去訪問局部變量;如果當前方法被銷燬,局部內部類對象還在堆內存中,依然持有對局部變量的引用,但是方法被銷燬的時候方法中的局部變量卻被銷燬了。
此時就會出現:在堆內存中,一個對象引用著一個不存在的變量,為了避免該問題,可以使用final修飾局部變量,從而變成常量,使之永駐內存空間,這樣即使方法被銷燬了,該局部變量也繼續存在在內存中,對象可以繼續持有。
局部內部類代碼案例如下:
<code>public class LocalInnerClass {
\t// 外部類靜態成員
\tstatic String name = "name";
\t\t
\tpublic static void main(String[] args) {
\t\tSystem.out.println("局部內部類");
\t\t
\t\tfinal String info = "info";
\t\t
\t\tclass InnerClass {
\t\t\t
\t\t\tString nick = "nick";
\t\t\t
\t\t\tSystem.out.println(name);
\t\t\tSystem.out.println(info);
\t\t\tSystem.out.println(nick);
\t\t
\t\t}
\t\tnew InnerClass().test();
\t}
}/<code>
匿名內部類
匿名內部類(Anonymous),是一個沒有名稱的局部內部類,適合只使用一次的類。在開發中會經常使用這樣的類,只需要定義一次,僅僅使用一次就可以不再使用了,此時就不應該再定義在一個類來存儲其功能邏輯。比如在Android的事件處理中,不同的按鈕點擊之後產生的不同的響應操作,首先選擇使用匿名內部類。
匿名內部類的語法格式:
<code>new 父類構造器([實參列表]) 或 接口()
{
//匿名內部類的類體部分
}/<code>
但是需要注意的是:匿名內部類必須繼承一個父類或者實現一個接口,但其最多隻能繼承一個父類或實現一個接口。
匿名內部類的特點:
1):匿名內部類本身沒有構造器,但是會調用父類構造器.
2):匿名類儘管沒有構造器,但是可以在匿名類中提供一段實例初始化代碼塊,JVM在調用父類構造器後,會執行該段代碼.
3):內部類處理可以繼承類之外,還可以實現接口.
匿名內部類代碼案例如下:下述代碼是安卓中的按鈕點擊事件處理邏輯
<code>
btnClick.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(MainActivity.this,
"按鈕被點擊", Toast.LENGTH_SHORT).show();
}
});/<code>
完結。
閱讀更多 老夫不正經 的文章