Java內部類學習筆記,Java類學習筆記
20160923
- 定義:將一個類的定義放在另一個類的內部;
- 從外部類的非靜態方法之外,建立某個內部類的對象:OutClassName.InnerClassName;
- 內部類擁有所有其外部類的成員的訪問權;
- 成員內部類不能含有static修飾的變數和方法,因為成員內部類需要先建立了外部類,才能建立它自己的
- 內部類中產生外部類對象的引用,可以使用OutClassName.this;
1 public class DoThis { 2 void f(){System.out.println("DoThis.f()");} 3 public class Inner{ 4 public DoThis getOuter(){ 5 return DoThis.this; 6 } 7 } 8 public Inner getInner(){ 9 return new Inner();10 }11 public static void main(String[] args) {12 DoThis dThis = new DoThis();13 DoThis.Inner dThisInner = dThis.getInner();14 dThisInner.getOuter().f();15 }16 }
1 public class DoNew {2 public class Inner{};3 public static void main(String[] args) {4 DoNew doNew = new DoNew();5 DoNew.Inner dInner = doNew.new Inner();6 }7 }
- 建立嵌套類(靜態內部類),不需要外部類對象的引用;
- private修飾的內部類,只能在其外部類內部訪問;protected修飾的內部類,只有其外部類、其外部類的子類、其外部類同一個包中的其他類可以訪問;
1 class Parcel4{ 2 private class PContents implements Contents { 3 private int i = 11; 4 @Override 5 public int value() { return i; } 6 } 7 protected class PDestination implements Destination { 8 private String label; 9 private PDestination(String whereTo) { label = whereTo; }10 @Override11 public String readLabel() { return label; }12 }13 public Destination destination(String s){ return new PDestination(s); }14 public Contents contents(){ return new PContents(); }15 Parcel4.PContents t;//PContents是private,只能在Parcel4內部訪問16 }17 public class TestParcel {18 public static void main(String[] args) {19 Parcel4 p = new Parcel4();20 Contents contents = p.contents();21 Destination destination = p.destination("Tasmania");22 //Parcel4.PContents pc = p.new PContents();//PContents是private,只能在Parcel4內部訪問,此處報錯23 }24 }
- 複雜的內部類:在方法或範圍內定義內部類,理由如下:
1、一個定義在方法中的類
1 public class Parcel5 { 2 public Destination destination(String s){ 3 class PDestination implements Destination{ 4 private String label; 5 private PDestination(String whereTo){ 6 label = whereTo; 7 } 8 @Override 9 public String readLabel() { return label; }10 }11 return new PDestination(s);12 }13 public static void main(String[] args) {14 Parcel5 p = new Parcel5();15 Destination destination = p.destination("Tasmania");16 }17 }
2、一個定義在範圍中的類,範圍在方法的內部
1 public class Parcel6 { 2 private void internalTracking(boolean b) { 3 if (b){ 4 class TrackingSlip { 5 private String id; 6 public TrackingSlip(String s) { 7 id = s; 8 } 9 String getSlip(){ return id;}10 }11 TrackingSlip ts = new TrackingSlip("slip");12 String s = ts.getSlip();13 }14 //Can't use it here!Out of scope:15 //TrackingSlip ts = new TrackingSlip("x");16 }17 public void track(){internalTracking(true);}18 public static void main(String[] args) {19 Parcel6 p = new Parcel6();20 p.track();21 }22 }
3、一個實現了介面的匿名類
4、一個匿名類,擴充了有非預設構造器的類
5、一個匿名類,執列欄位初始化
6、一個匿名類,通過執行個體初始化實現構造(匿名類沒有構造器)
- 傳遞給匿名內部類的參數,並且在匿名內部類中使用,該參數須定義為final;
- 匿名內部類可擴充類,也可以實現介面,但不能同時;如果實現介面,只能實現一個介面;
- 《Java編程思想》199頁,10.6.1再訪Factory 方法,使用匿名內部類的例子,非常好;
- 嵌套類:static修飾的內部類,無法訪問非靜態外部類對象
- 嵌套類可以作為介面的一部分,甚至實現外部介面
-
1 public interface ClassInInterface { 2 void howdy(); 3 class Test implements ClassInInterface{ 4 @Override 5 public void howdy() { System.out.println("Howdy"); } 6 public static void main(String[] args){ 7 new Test().howdy(); 8 } 9 }10 }
- 內部類能夠多層嵌套,並且能夠透明的訪問所有它嵌入的外部類的成員
-
1 class A{ 2 private void f(){} 3 class B { 4 private void g(){} 5 public class C { 6 void h() { 7 g(); 8 f(); 9 }10 }11 }12 }13 public class MultiNestingAccess {14 public static void main(String[] args) {15 A a = new A();16 A.B ab = a.new B();17 A.B.C abc =ab.new C();18 abc.h();19 }20 }
- 為什麼需要內部類?
- 《Java編程思想》204頁解釋為:每個內部類都能獨立的繼承自一個(介面的)實現,所以無論外圍類是否已經繼承了某個(介面的)實現,對於內部類都沒有影響;
- 簡單講就是,內部類實現介面、繼承某個類,比外部類實現介面少了許多顧慮,外部類實現介面需要考慮全面,在其他地方是否有影響;
- 內部類可以繼承多個具體類或抽象類別,與介面配合,使“多重繼承”的解決方案變得完美;
- 內部類可以有多個執行個體,每個執行個體都有自己的狀態資訊,並且與外部類對象相互獨立;
- 在單個外部類中,可以使多個內部類以不同的方式實現同一個介面,或繼承同一個類;
- 內部類對象的建立,並不依賴於外部類對象的建立
- 內部類沒有“is-a”關係,內部類是獨立的實體
- 閉包,記錄了建立閉包的範圍的一些資訊,使得閉包可調用其外部範圍資料;內部類就是物件導向的閉包;
- 回調,
- 通過內部類提供閉包功能舉例:
-
1 package com.helei.innerclasses; 2 interface Incrementable { 3 void increment(); 4 } 5 class Callee1 implements Incrementable { 6 private int i = 0; 7 @Override 8 public void increment() { 9 i++;10 System.out.println(i);;11 }12 }13 class MyIncrement {14 public void increment() { System.out.println("Other operation");}15 static void f(MyIncrement mi) {mi.increment();}16 }17 class Callee2 extends MyIncrement {18 private int i = 0;19 public void increment() {20 super.increment();21 i++;22 System.out.println(i);23 }24 private class Closure implements Incrementable {25 public void increment() {26 Callee2.this.increment();27 }28 }29 Incrementable getCallbackReference() {30 return new Closure();31 }32 }33 class Caller {34 private Incrementable callbackReference;35 Caller(Incrementable cbh){callbackReference = cbh;}36 void go() {callbackReference.increment();}37 }38 public class Callbacks {39 public static void main(String[] args) {40 Callee1 c1 = new Callee1();41 Callee2 c2 = new Callee2();42 MyIncrement.f(c2);43 Caller caller1 = new Caller(c1);44 Caller caller2 = new Caller(c2.getCallbackReference());45 caller1.go();46 caller1.go();47 caller2.go();48 caller2.go();49 }50 }
- 看了好幾遍才梳通了以上流程,最好能夠敲一遍,通過debug調試過一遍
- 內部類與控制架構
- 內部類的繼承
- 內部類覆蓋,無效;可以顯式繼承某內部類;
- 局部內部類,與匿名內部類的區別