將一個類的定義放在另外一個類的內部,這就是內部類。內部類是Java一種很是有用的特徵,由於他容許你把一些邏輯相關的數據組織在一塊兒,並控制它的可見性。java
咱們都知道類的建立語法(簡略)以下 閉包
[public |...] class 類名 [implements|....]{ 定義屬性(注意不一樣的修飾符(如public ....)) 定義方法語法(構造方法或普通方法) }
而內部類的建立就是把該類放在外部類的 同屬性的位置或方法(包括構造方法)內 定義例下(但願你們能夠看懂)eclipse
public class OutClass{
public OutClass(){ //構造方法內建立內部類
class C{}
} (修飾符)class A{} #局部內部類(同屬性的位置) public B getB(){ #簡稱方法內部類(方法的內部) class B{}
return new B(); } }
####在次都忽略了修飾符,若是加上了修飾符如(static | public |private),會影響內部類的可見範圍或和外圍類的關係(如static),詳細信息可參考修飾
符(和修飾符的用法及其相識)的講解,和下文,由於篇幅有限不可能全面講到。
內部類的建立方式有兩種
方法一:在外圍類環境下(),直接經過new 關鍵字和普通類同樣建立
方法二:經過外圍類實例建立,具體細節以下
public class Parcel2 { class Contents{ private int i = 11; public int values() { return i; } } public Contents contents() { return new Contents(); #在外部類環境內建立(方法一) } public static void main(String[] args) { Parcel2 parcel2 = new Parcel2(); #注意這是兩種建立內部類的方法 Contents contents = parcel2.contents(); #在外部類環境內直接建立 Contents contents = parcel2.new Contents();#經過外部類對象和關鍵字new建立內部類 (方法二) } }
備註:其它不少博客對內部類作了分類,這些分類也不外乎就是定義內部時用的修飾符和內部類定義位置的不一樣給內部起的名字而已。例如ide
成員內部類:同屬性同樣定義(修飾符通常是public或private)。測試
匿名內部類:即一個方法接受一個接口(interfaceA)類型的類。在其它類中調用這個方法,直接經過new interfaceA()這個接口並實現了該接口的全部方法,new interfaceA就是匿名內部了。this
方法內部類:就是定義在外類普通方法內的內部類。spa
局部內部類:就是定義在構造方法內的內部類。code
嵌套內部類:就是把定義內部了時用static關鍵字修飾的內部類。這個類我想多說點,普通內部類對象隱式的保存了一個外部類對象的引用,然而內部類經過static修飾就不同了,該內部類就和外部類徹底分離了,即不須要經過外部類對象建立內部類,內部了沒有關聯的外部類引用了。對象
接口內部類:外部類不是一個類,而是一個接口,接口內定義了一個內部類,該內部類能夠實現本身,案例如五 接口內部了blog
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中內部類這一節講到了閉包的概念,他是這樣定義閉包的:閉包是一個可調用的對象,它記錄了一些信息(即外部類對象的一些信息,這些信息並無顯現的展現給內部了對象,而是以一種特殊的形式OutClass_name.this的形式展現給了本身),這些信息來自建立它的做用域。經過這個定義,能夠看出內部類是面向對象的閉包(即內部類就是java中一種閉包),它不只包含外圍類對象的信息,還自動擁有一個指向外部類的引用,在此做用域內,內部類能夠有權操做全部成員,包括private成員。