能夠把一個類的定義放在另外一個類的定義內部,這就是內部類。
Java最晦澀的部分之一。
內部類看起來就像是一種代碼隱藏機制,將類只與其餘類的內部。但遠不止如此,內部類瞭解外部類,並能與之通訊。shell
建立內部類的方式就如同你想的同樣——把類的定義置於外圍類的裏邊設計模式
.this
。這樣產生的引用自動地具備正確類型,這一點在編譯期就被知曉並收到檢查,所以沒有任何運行開銷。.new
建立內部類。public class Outer { void func() { System.out.println("Test"); } class Inner { void func() { System.out.println("Inner"); // .this語法 Outer.this.func(); } } public static void main(String[] args) { // .new語法 new Outer().new Inner().func(); } }
內部類的優勢:能夠更好的隱藏細節
特色:安全
static
域和方法。能夠在一個方法或任意做用域內定義內部類,成爲局部內部類。這麼作的理由:閉包
public class Outer { public void func() { // 方法內部的內部類 class InnerMethod { void func() { System.out.println("class in method"); } } new InnerMethod().func(); } public void f() { if(true) { // 做用域內部的內部類 class InnerScope { void func() { System.out.println("class in scope"); } } new InnerScope().func(); } } public static void main(String[] args) { new Outer().func(); new Outer().f(); } }
InnerScope
類被嵌套到if
語句中,這並非說該類到建立是有條件的,他跟其餘的類同樣被編譯過了。final
的局部變量。static
方法,則只能訪問static
修飾的成員變量。final
或abstract
修飾。inner()
方法將返回值的生成與表示這個返回值的類定義結合在一塊兒,並且這個類沒有名字。public class Outer { private final String outerStr = "Outer"; class Inner { public Inner(String str) { System.out.println("Inner Constructor " + str); } public void func() { System.out.println("Inner"); } } public Inner inner() { return new Inner("Dota") { { // 跟構造方法同樣初始化 str3 = "LOL"; } private String str1 = Outer.this.outerStr; private String str2 = outerStr; private String str3; @Override public void func() { System.out.println(str1); System.out.println(str2); System.out.println(str3); } }; } public static void main(String[] args) { new Outer().inner().func(); } }
Inner
的引用。new Inner()
中傳遞參數給基類的構造器。final
的。str1
和str2
是同樣的str
不要求是final
的,由於str
是傳遞給基類的構造器的,匿名內部類沒法使用。代碼更加簡潔框架
若是不須要內部類對象與其外圍對象之間有聯繫,那麼能夠將內部類聲明爲static
。ide
static
域和static
方法,但嵌套類能夠有。main
方法來實現調試。回調函數的定義:在計算機程序設計中,回調函數是指經過函數參數傳遞到其它代碼的,某一塊可執行代碼的引用。這一設計容許了底層代碼調用在高層定義的子程序。
非回調函數的場景:一個程序B
有一個方法b()
,要調用程序A
中的另外一個方法a()
。這個很簡單,只須要在程序B
的方法b()
中new A().a()
就能夠了。
回調函數:跟上述同樣,可是程序A
中的方法a()
在完成任務後,還會調用一個預約義好的回調函數;B
在方法b()
中,能夠按照預約義好的回調函數接口實現相關邏輯,而後把這段邏輯傳遞給A
,這樣在B.b()
調用A.a()
的時候,就會執行這段邏輯。函數
// A定義好的回調接口 interface Callback { void callback(); } // A定義 public class A { Callback callback; public A(Callback callback) { this.callback = callback; } public void a() { System.out.println("a"); callback.callback(); } } class B { public static void main(String[] args) { A a = new A(new Callback() { @Override public void callback() { System.out.println("callback"); } }); a.a(); } } // Output: a callback
控制框架是一類特殊的應用程序框架,他用來解決響應事件的需求。主要用來響應事件的系統被稱爲事件驅動系統。this
public class Test { private boolean light; private boolean water; class LightEvent extends SwitchEvent { @Override public void on() { light = true; } @Override public void off() { light = false; } } class WaterEvent extends SwitchEvent { @Override public void on() { water = true; } @Override public void off() { water = false; } } } abstract class SwitchEvent { public abstract void on(); public abstract void off(); }
上述代碼描述了一個開關事件的抽象類,和兩個繼承該抽象類的內部類。這些內部類可以自由地訪問Test
類中的字段,無需任何條件。設計
記得看!!!指針
public class Test extends Outer.Inner { // 若是沒有下面的構造方法會編譯失敗 public Test(Outer outer) { outer.super(); } } class Outer { class Inner {} }
Test
只繼承了內部類Inner
,而不是外部類。outer.super();
public class Test extends Outer { class Inner {} } class Outer { class Inner {} }
上述代碼中:Test
繼承了Outer
並「覆蓋」了Inner
,但這沒有用;這兩個Inner
是徹底絕不相干但兩個類,各自活在各自的命名空間裏。
public class Test extends Outer { class Inner extends Outer.Inner { @Override void func() { System.out.println("Test.Inner.func()"); } } public Test() { setInner(new Inner()); } public static void main(String[] args) { new Test().getInner().func(); } } class Outer { private Inner inner; class Inner { void func() { System.out.println("Outer.Inner.func()"); } } public Inner getInner() { return inner; } public void setInner(Inner inner) { this.inner = inner; } }
上述代碼中:Test
繼承了Outer
,Test.Inner
繼承了Outer.Inner
。此時若是覆蓋Inner中的方法,當構造器調用setInner(new Inner());
的時候,是把Test.Inner
向上轉型爲Outer
中的引用inner
。
(見10.5)
前面提到過,能夠在代碼塊裏建立內部類,典型的方式是在方法體內。
局部內部類不能有訪問說明符,由於他不是外部類的一部分。
局部內部類能夠訪問當前代碼塊內的常量,以及此外圍類的成員。
每一個類都會產生一個.class文件,其中包含了如何建立該類的對象的所有信息(此信息產生一個「meta-class」,叫作Class;對象),內部類也是如此。
$
內部類名.class$
編譯器分配的數字.class$
分割.class對於Unix shell而言,$
是一個元字符,因此在列出.class文件的時候,有時會有問題。
內部類涉及內容相對複雜,多花點時間吧~