標籤:java 內部類 樣本 解析 總結
一、引言
由於目前是Android開發的實習生,在開發過程中發現越來越多自己知道但是真正去使用的時候卻用不上的情況,比如內部類的使用上,所以在經過網上尋找資料學習以及自己總結之後,特此發表一篇博文與大家分享,如有不當之處,萬望指出。
二、內部類內部類是指在一個外部類的內部再定義一個類,是一個編譯時間的概念,一旦編譯成功,內部類與其外部類就會成為完全不同的兩類,只是內部類的前面會冠以外部類的類名和$符號,如一個outer類內部定義了一個inner的內部類,那麼編譯完成後會產生outer.class和outer$inner.class兩個類,因此內部類的成員變數與方法可以與外部類相同。從內部類的定義上來看,其實內部類嚴重破壞了良好的代碼結構,那麼為什麼還要使用內部類呢?因為內部類可以隨意使用外部類的成員變數(包括私人的)而不用產生外部類對象,這也是內部類的唯一優點。三、內部類的分類及樣本 內部類分為成員內部類、局部內部類、靜態內部類和匿名內部類。下面針對各個內部類進行介紹: (1)成員內部類
作為外部類的一個成員存在,與外部類的屬性、方法並列。成員內部類中可以訪問外部類的所有成員,當外部類的變數與內部類的變數名重複時,使用外部類名.this.變數名可以對外部類的變數進行調用,如果沒有重複時可直接使用變數名進行調用。在普通外部類方法中訪問靜態內部類可new出成員內部類對象進而直接調用其中的方法,而在靜態外部類方法中需要先new出外部類對象,再調用外部類對象名.new 內部類的方式來獲得成員內部類對象。
成員內部類中不能定義靜態變數,因為成員內部類需要先建立了外部類,才能建立它自己的。
成員內部類可以使用外部類的私人成員和屬性,同時其在外部類中定義了不可訪問的屬性,這樣就在外部類中實現了比外部類的private還要小的存取權限。
範例程式碼如下:
/** * * @ClassName: MemberInnerClass * @Description: 成員內部類 * @author ADAM * @date 2014年7月25日 上午9:20:28 * */public class MemberInnerClass {private int i = 0;public class Inner {// 成員內部類可加許可權修飾符int i = 3;public void print() {System.out.println(i);// 輸出為內部類的i,值為3System.out.println(this.i);// 輸出為內部類的i,值為3System.out.println(MemberInnerClass.this.i);// 輸出外部類的i,值為0}}public void print() {(new Inner()).print();// 外部類普通方法調用成員內部類直接new出內部類進行調用}public static void main(String[] args) {((new MemberInnerClass()).new Inner()).print();// 外部類靜態方法中調用成員內部類首先new出外部類然後new出內部類進行調用}}
(2)局部內部類
即在方法中定義的內部類,與局部變數類似,在局部內部類前不加修飾符public或private,其範圍為定義它的代碼塊。局部內部類中不可定義靜態變數,可以訪問外部類(即方法)中的變數,但是變數必須是final。局部內部類與外部類的命名重名時的調用方法與成員內部類相同,訪問局部內部類必須得先有外部類對象。
在類外不可直接產生局部內部類(保證局部內部類對外是不可見的)。要想使用局部內部類時需要產生外部類對象,對象再去調用方法,在方法中才能調用其局部內部內。通過內部類與介面達到了一個強制的弱耦合,用局部內部類來實現介面,並在方法中返回介面類型,使局部內部類不可見,屏蔽實作類別的可見度。
範例程式碼如下:
/** * * @ClassName: LocalInnerClass * @Description: 局部內部類 * @author ADAM * @date 2014年7月25日 上午10:36:26 * */public class LocalInnerClass {private int j = 3;private int i = 2;public void test() {MemberInnerClass memberInnerClass = new MemberInnerClass();// 若要訪問其他類中的成員內部類只能當該成員內部類的修飾符為public才可// 否則編譯錯誤,即成員內部類可以再類內部實現比private還要小的許可權memberInnerClass.new Inner();final int i = 0;class Inner {// 此處不得加上private等修飾符,否則編譯錯誤int i = 1;public void print() {System.out.println(j);飾符,否則編譯錯誤System.out.println(i);// 此時輸出局部內部類的i,外部方法中的變數只能通過傳參的形式進行調用System.out.println(LocalInnerClass.this.i);// 此時輸出的是外部類中的i}}Inner inner = new Inner();// 局部內部類只能在方法內執行個體化並進行調用inner.print();}public static void main(String[] args) {(new LocalInnerClass()).test();}}
局部內部類不僅可以定義在方法中還可以定義在範圍內。以下提供兩個Thinking in Java的例子
定義在方法內:
public class Parcel4 { public Destination destination(String s) { class PDestination implements Destination { private String label; private PDestination(String whereTo) { label = whereTo; } public String readLabel() { return label; } } return new PDestination(s); } public static void main(String[] args) { Parcel4 p = new Parcel4(); Destination d = p.destination("Tasmania"); } } <span style="line-height: 1.3em; font-family: 'Courier New', monospace; background-color: inherit;"> </span>
定義在範圍裡:
public class Parcel5 { private void internalTracking(boolean b) { if (b) { class TrackingSlip { private String id; TrackingSlip(String s) { id = s; } String getSlip() { return id; } } TrackingSlip ts = new TrackingSlip("slip"); String s = ts.getSlip(); } } public void track() { internalTracking(true); } public static void main(String[] args) { Parcel5 p = new Parcel5(); p.track(); } }
局部內部類也像別的類一樣進行編譯,只是範圍有所不同,只在該方法或者條件的範圍內才能使用,出了這些範圍則無法被使用。
(3)靜態內部類
靜態內部類也稱為嵌套內部類,定義在類中,任何方法外,用static定義,靜態內部類中可以定義靜態或非靜態成員,其可用public、private等修飾符修飾,一般使用public修飾,方便調用,其只能訪問外部類中的靜態成員。外部類訪問靜態內部類中的靜態成員時直接使用內部類.靜態成員,訪問靜態內部類的非靜態成員時先執行個體化靜態內部類再通過對象訪問。
產生一個靜態內部類不需要外部類對象成員,這是與成員內部類的區別,同時普通內部類不能有static方法和屬性,也不能包含嵌套類,靜態內部類的對象可以直接產生:外部類.內部類 對象名= new 外部類.內部類()即可
注意:當類與介面(或者介面與介面)發生方法命名衝突時,必須使用內部類來實現。用介面不能完全地實現多繼承,用介面配合內部類才能實現真正的多繼承。
範例程式碼如下:
/** * * @ClassName: StaticInnerClass * @Description: 靜態內部類 * @author ADAM * @date 2014年7月25日 上午10:37:04 * */public class StaticInnerClass {private int i = 1;public static int j = 1;public int k = 0;public static class Inner {private int i = 0;private static int j = 0;// 可定義靜態與非靜態成員public static void print() {//System.out.println(k);// 編譯錯誤,不得調用外部類中的非靜態成員System.out.println(new StaticInnerClass().i);//訪問外部類中的非靜態成員變數需要先執行個體化外部類System.out.println(j);System.out.println(new StaticInnerClass().j);// 靜態內部類使用外部類中的靜態成員}}public static void main(String[] args) {Inner.print();// 外部類靜態方法或者非靜態方法調用靜態內部類中的靜態成員時直接內部類名.成員即可StaticInnerClass.Inner inner = new StaticInnerClass.Inner();// 靜態內部類的執行個體化不需要先執行個體化外部類System.out.println(inner.i);// 訪問靜態內部類中的非靜態成員時需要先執行個體化靜態內部類}}
通過內部類實現多繼承範例程式碼如下:
/** * * @ClassName: Pencil * @Description: 筆類 * @author ADAM * @date 2014年7月25日 上午10:42:59 * */public abstract class Pencil {public abstract void write();}/** * * @ClassName: Eraser * @Description: 橡皮擦類 * @author ADAM * @date 2014年7月25日 上午10:43:28 * */public abstract class Eraser {public abstract void erase();}/** * * @ClassName: PencilWithEraser * @Description: 多繼承類 * @author ADAM * @date 2014年7月25日 上午10:43:53 * */public class PencilWithEraser {private MyPencil pencil = new MyPencil();private MyEraser eraser = new MyEraser();private class MyPencil extends Pencil {//繼承筆類@Overridepublic void write() {System.out.println("To Write");}}private class MyEraser extends Eraser {//繼承橡皮擦類@Overridepublic void erase() {System.out.println("To Erase");}}// 本類自己的方法,調用繼承類中的方法public void write() {pencil.write();}public void erase() {eraser.erase();}public static void main(String[] args) {PencilWithEraser pencilWithEraser = new PencilWithEraser();pencilWithEraser.write();pencilWithEraser.erase();}}
(4)匿名內部類 用於繼承其他類或是實現介面,並不需要增加額外的方法,只是對繼承方法的重寫或實現,也使用於只是為了得到一個對象執行個體,不需要知道其實際類型,此時類名是沒有意義的,也不需要被使用到。
範例程式碼如下:
/** * * @ClassName: AnonymousInnerClass * @Description: 匿名內部類 * @author ADAM * @date 2014年7月25日 上午10:38:25 * */public class AnonymousInnerClass {public void click(OnClickListener onClickListener) {System.out.println("click,click");}public static void main(String[] args) {AnonymousInnerClass anonymousInnerClass = new AnonymousInnerClass();anonymousInnerClass.click(new OnClickListener() {// 直接new出匿名內部類,不需要儲存對象,一般用於繼承其他類或是實現介面@Overridepublic void onClick() {System.out.println("Inner Click");}});}}
四、總結 由於目前還是處於學習階段,對於內部類的使用最多的也是成員內部類和匿名內部類,所以對於諸如非常細緻地去區分各個內部類的使用情境以及涉及到的更小的存取權限的作用等方面體會並不是很深刻,之後有更進一步的學習會補上,也希望看到這篇博文的朋友如果有一些其他的見解或者補充或者是推薦學習的資料也可以提出來,這篇博文也是借鑒網上各位大神以及百科的相關資料,再自己手動編碼驗證總結出來的,感恩各位大神,謝謝。