ThinkInJava之內部類
一:內部類概述
將一個類的定義放在另一個類的內部,這就是內部類。內部類是Java一種非常有用的特徵,因為他允許你把一些邏輯相關的資料組織在一起,並控制它的可見性。
二:內部類的建立
我們都知道類的建立語法如下
[public |...] class 類名 [implements|....]{ 定義屬性(注意不同的修飾符(如public ....)) 定義方法語法(構造方法或普通方法) }
而內部類的建立就是把該類放在同屬性或方法內定義例如
public class OutClass{ (修飾符)class A{} #區域性內部類 public B getB(){#簡稱方法內部類 class B{} return new B(); } }
三:外部類訪問(建立)內部類(和內部類的修飾符有關係(如private public static 。。。。))
public class Parcel2 { class Contents{ private int i = 11; public int values() { return i; } } public Contents contents() { return newContents(); #在外部類環境內建立 } public static void main(String[] args) { Parcel2 parcel2 = new Parcel2(); #注意這是兩種建立內部類的方法 Contents contents = parcel2.contents(); #在外部類環境內直接建立 Contents contents = parcel2.new Contents();#通過外部類物件和關鍵字new建立內部類 } }
備註:其它很多部落格對內部類做了分類,這些分類也不外乎就是定義內部時用的修飾符和內部類定義位置的不同給內部起的名字而已。例如
成員內部類:同屬性一樣定義(修飾符一般是public或private)。
匿名內部類:即一個方法接受一個介面(interfaceA)型別的類。在其它類中呼叫這個方法,直接通過new interfaceA()這個介面並實現了該介面的所有方法,new interfaceA就是匿名內部了。
方法內部類:就是定義在外類普通方法內的內部類。
區域性內部類:就是定義在構造方法內的內部類。
巢狀內部類:就是把定義內部了時用static關鍵字修飾的內部類。這個類我想多說點,普通內部類物件隱式的儲存了一個外部類物件的引用,然而內部類通過static修飾就不一樣了,該內部類就和外部類完全分離了,即不需要通過外部類物件建立內部類,內部了沒有關聯的外部類引用了。
介面內部類:外部類不是一個類,而是一個介面,介面內定義了一個內部類,該內部類可以實現自己,案例如五 介面內部了
四:關鍵字this 和new
4.1 new 的用法已經介紹過(通過外部類例項建立內部類例項)
4.2 this 通過OutClass.this 方式可訪問建立自自己的的外部類例項(非常重要注意理解,有助於幫助我們理解為什麼外部類物件的屬性(包括private)完全報漏給內部類,檢驗如下
public class OutClass { void print() { System.out.println("id:"+ this.hashCode()+"我是外部類的方法"); } class InnerClass{ void print() { System.out.println("我是內部類的方法"); System.out.println("___________"); OutClass.this.print();//內部類內訪問建立它的外部類例項,並呼叫外部類的方法 } } public static void main(String[] args) { OutClass outClass = new OutClass(); System.out.println("id:" + outClass.hashCode()); InnerClass innerClass = outClass.new InnerClass(); innerClass.print(); } } 結果: id:865113938 我是內部類的方法 ___________ id:865113938我是外部類的方法 分析結果,我們發現列印的hashCode()值相同,可知兩次列印都是同一個物件的引用地址。
五:介面內部類
正常情況下,不能在介面內放置任何程式碼,但巢狀類可以作為介面的一部分,你放入介面中的任何類都自動轉化為public和static,因為類是static,只是將
巢狀類置於介面的名稱空間內,這並不違反介面規則。你可以在內部類中實現外圍介面如下
public interface ClassInInterface { void howdy(); class Test implements ClassInInterface{ @Override public void howdy() { System.out.println("我是介面內部類介面"); }; public static void main(String[] args) { new Test().howdy(); } } } 注意:在編譯器內(eclipse),無法直接執行該main方法,可通過Javac編譯程式碼,然後用Java命令執行 備註:如果你想建立某些公共程式碼,只想讓默些特定類(實現了該介面的類)擁有。就可用該介面內部了特性。
測試:ClassInInterface public class ClassInInterfaceImpl implements ClassInInterface{ @Override public void howdy() { new Test().howdy(); System.out.println("我自己的方法"); } public static void main(String[] args) { ClassInInterfaceImpl classInInterfaceImpl = new ClassInInterfaceImpl(); classInInterfaceImpl.howdy(); } } 結果: 我是介面內部類介面 我自己的方法
六:關於使用內部類的一些小結 6.1:解決了java多重繼承的問題。比如有個類需要繼承其它兩個類,然而Java只支援單繼承,故我們可以通過編寫一個內部類來繼承另一個類的我們需要的類(當然我們也可以通過組合的方式來完成相識功能) 6.2:封裝一些功能,只讓特定的類擁有該方法。例如介面內部類,只有實現了該介面的類才擁有使用特定功能。 6.3:一個類中要實現一個介面方法的不同功能。 何時(什麼情況下)使用內部類?請注意這個問題(引用ThinkInJava),如果只是需要一個介面的引用,為什麼不通過外圍類實現那個介面呢?答案是:如果這能滿足需求,那麼就行該這樣做(即不用內部類) 同時,因為內部類引用了外部類的物件的地址,導致外部類始終有一個物件在引用他,如果不刻意手動清空內部類,就會導致記憶體洩漏。如下 public class Clear { @Override protected void finalize() throws Throwable { // TODO Auto-generated method stub super.finalize(); System.out.println("垃圾回收器要清理我"); } public static void main(String[] args) { Clear clear = new Clear(); 程式碼1.//InnerClass innerClass = clear.new InnerClass(); 程式碼2.//innerClass = null 程式碼3.//new Clear().new InnerClass() clear = null;// System.gc(); } class InnerClass{ } } 結果:垃圾回收器要清理我 如果我們把程式碼1注射開啟,就不會執行finalize()方法,必須同時把程式碼2也要開啟。如果是程式碼3的寫法?那麼垃圾怎麼回收外部類呢??(就導致了記憶體洩漏) 備註:在thinkInJava中內部類這一節講到了閉包的概念,他是這樣定義閉包的:閉包是一個可呼叫的物件,它記錄了一些資訊,這些資訊來自建立它的作用域。通過這個定義,可以看出內部類是面向物件的閉包,它不僅包含外圍類物件的資訊,還自動擁有一個指向外部類的引用,在此作用域內,內部類可以有權操作所有成員,包括private成員。