摘要:但遠(yuǎn)不止如此,內(nèi)部類了解外部類,并能與之通信。內(nèi)部類還擁有其外圍類的所有元素的訪問權(quán)。普通內(nèi)部類內(nèi)不能有域和方法。特點普通內(nèi)部類對象隱式的保存了外部類對象,但嵌套類并非如此。局部內(nèi)部類可以訪問當(dāng)前代碼塊內(nèi)的常量,以及此外圍類的成員。
點擊進入我的博客
可以把一個類的定義放在另一個類的定義內(nèi)部,這就是內(nèi)部類。
Java最晦澀的部分之一。
內(nèi)部類看起來就像是一種代碼隱藏機制,將類只與其他類的內(nèi)部。但遠(yuǎn)不止如此,內(nèi)部類了解外部類,并能與之通信。
創(chuàng)建內(nèi)部類的方式就如同你想的一樣——把類的定義置于外圍類的里邊
10.2 鏈接到外部類當(dāng)生成一個內(nèi)部類的對象時,此對象與制造它的外部對象之間就有了一種聯(lián)系,所以它能訪問其外圍對象的所有成員。
內(nèi)部類還擁有其外圍類的所有元素的訪問權(quán)。當(dāng)某個外部類當(dāng)對象創(chuàng)建了一個內(nèi)部類對象時,此內(nèi)部類對象必定會秘密地捕獲一個指向那個外部類對象當(dāng)引用。當(dāng)你訪問外部類成員時,就是用那個引用來選擇外部類當(dāng)成員。
10.3 使用.this與.new如果你需要生成對外類對象的引用,可以使用外部類.this。這樣產(chǎn)生的引用自動地具有正確類型,這一點在編譯期就被知曉并收到檢查,因此沒有任何運行開銷。
通過外部類的對象創(chuàng)建內(nèi)部類(非static內(nèi)部類)對象,可以通過外部類.new創(chuàng)建內(nèi)部類。
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(); } }10.4 內(nèi)部類與向上轉(zhuǎn)型
內(nèi)部類的優(yōu)點:可以更好的隱藏細(xì)節(jié)
特點:
外部類可以訪問內(nèi)部類的所有元素,無論什么修飾符。
普通內(nèi)部類內(nèi)不能有static域和方法。
一個內(nèi)部類可以被嵌套多層,而且可以訪問所有外圍類的成員。
10.5 局部內(nèi)部類可以在一個方法或任意作用域內(nèi)定義內(nèi)部類,成為局部內(nèi)部類。這么做的理由:
你實現(xiàn)了某類型的接口,于是可以創(chuàng)建并返回對其的引用
你要解決一個復(fù)雜的問題,想創(chuàng)建一個類來復(fù)制你的解決方案,但又不希望這個類是公共可用的。
public class Outer { public void func() { // 方法內(nèi)部的內(nèi)部類 class InnerMethod { void func() { System.out.println("class in method"); } } new InnerMethod().func(); } public void f() { if(true) { // 作用域內(nèi)部的內(nèi)部類 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(); } }
局部內(nèi)部類類似方法的局部變量,所以在類外或者類的其他方法中不能訪問這個內(nèi)部類。但這并不代表局部內(nèi)部類的實例和定義了它的方法中的局部變量具有相同的生命周期。
可以在同一個子目錄(包)下起一個跟局部內(nèi)部類相同的類,不會有沖突。
InnerScope類被嵌套到if語句中,這并不是說該類到創(chuàng)建是有條件的,他跟其他的類一樣被編譯過了。
因為不存在外部可見性,局部內(nèi)部類不能用權(quán)限修飾符。
不能在局部內(nèi)部類中使用可變的局部變量,可以使用final的局部變量。
可以訪問外圍類的成員變量。如果是static方法,則只能訪問static修飾的成員變量。
可以使用final或abstract修飾。
10.6 匿名內(nèi)部類inner()方法將返回值的生成與表示這個返回值的類定義結(jié)合在一起,而且這個類沒有名字。
創(chuàng)建一個繼承某個類(或者實現(xiàn)某個接口)的匿名類對象。
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") { { // 跟構(gòu)造方法一樣初始化 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(); } }
返回的類型被自動向上轉(zhuǎn)型成Inner的引用。
如果構(gòu)造方法帶參數(shù),也可以在new Inner()中傳遞參數(shù)給基類的構(gòu)造器。
在匿名內(nèi)部類定義字段時,可以初始化。
在匿名內(nèi)部類使用外部類的對象時,只能使用final的。
str1和str2是一樣的
匿名內(nèi)部類沒有名字,也就沒有構(gòu)造器,但是可以通過實例初始化模擬構(gòu)造器。但是你不能重載實例初始化方法,所以只能有一個這樣的構(gòu)造器。
變量str不要求是final的,因為str是傳遞給基類的構(gòu)造器的,匿名內(nèi)部類無法使用。
匿名內(nèi)部類可以繼承類或者實現(xiàn)接口,但不能兩者兼得。
10.6.1 再訪工廠方法代碼更加簡潔
10.7 嵌套類(靜態(tài)內(nèi)部類)如果不需要內(nèi)部類對象與其外圍對象之間有聯(lián)系,那么可以將內(nèi)部類聲明為static。
普通內(nèi)部類對象隱式的保存了外部類對象,但嵌套類并非如此。
要創(chuàng)建嵌套類的對象,并不需要外部類的對象
不能從嵌套類對象中訪問外部類的非靜態(tài)對象。
普通內(nèi)部類不能有static域和static方法,但嵌套類可以有。
10.7.1 接口內(nèi)部的類嵌套類可以作為接口的一部分,還可以實現(xiàn)其外部接口。
如果你想創(chuàng)建某些公共代碼,使得它們可以被某個接口的所有不同實現(xiàn)所共用,那么使用接口內(nèi)部的嵌套類會很方便。
可以使用嵌套類的main方法來實現(xiàn)調(diào)試。
10.7.2 多層嵌套一個內(nèi)部類可以嵌套多層
一個嵌套類也可以被嵌套多層。
10.8 為什么需要內(nèi)部類外部類可以有多個內(nèi)部類,每個內(nèi)部類都能獨立的繼承自一個(接口的)實現(xiàn),所以無論外圍類是否已經(jīng)繼承了某個(接口的)實現(xiàn),對于內(nèi)部類都沒有影響。
接口解決類部分“多重繼承”,內(nèi)部類補充的實現(xiàn)了“多重繼承。
內(nèi)部類可以有多個實例,每個實例都有自己的狀態(tài)信息,并且與外圍類對象的信息相互獨立。
再單個外圍類中,可以讓多個內(nèi)部類以不同的方式實現(xiàn)同一個接口。
創(chuàng)建內(nèi)部類對象的時候并不一定依賴外部類對象的創(chuàng)建。
內(nèi)部類并沒有令人迷惑的“is-a”關(guān)系,他就是一個獨立的實體。
10.8.1 閉包與回調(diào)閉包(closure)是一個可調(diào)用的對象,它記錄了一些信息,這些信息來自于創(chuàng)建它的作用域。
通過上述定義,可以看出內(nèi)部類就是面向?qū)ο蟮拈]包,因為它不僅包含外圍類對象(創(chuàng)建內(nèi)部類的作用域)的信息,還自動擁有一個指向此外圍類對象的引用,在此作用域內(nèi),內(nèi)部類有權(quán)操作所有成員。
通過內(nèi)部類實現(xiàn)閉包的功能是優(yōu)良的解決方案,它比指針更靈活、更安全。
回調(diào)函數(shù)的定義:在計算機程序設(shè)計中,回調(diào)函數(shù)是指通過函數(shù)參數(shù)傳遞到其它代碼的,某一塊可執(zhí)行代碼的引用。這一設(shè)計允許了底層代碼調(diào)用在高層定義的子程序。
非回調(diào)函數(shù)的場景:一個程序B有一個方法b(),要調(diào)用程序A中的另一個方法a()。這個很簡單,只需要在程序B的方法b()中new A().a()就可以了。
回調(diào)函數(shù):跟上述一樣,但是程序A中的方法a()在完成任務(wù)后,還會調(diào)用一個預(yù)定義好的回調(diào)函數(shù);B在方法b()中,可以按照預(yù)定義好的回調(diào)函數(shù)接口實現(xiàn)相關(guān)邏輯,然后把這段邏輯傳遞給A,這樣在B.b()調(diào)用A.a()的時候,就會執(zhí)行這段邏輯。
// A定義好的回調(diào)接口 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 callback10.8.2 內(nèi)部類與控制框架
應(yīng)用程序框架就是被設(shè)計用來解決某類特定問題的一個或者一組類。
要運用某個應(yīng)用程序框架,通常是繼承一個或多個類,并覆蓋某些方法。在覆蓋后的方法中,編寫代碼定制應(yīng)用程序框架提供的通用解決方案(這是模板方法的一個例子)。
控制框架是一類特殊的應(yīng)用程序框架,他用來解決響應(yīng)事件的需求。主要用來響應(yīng)事件的系統(tǒng)被稱為事件驅(qū)動系統(tǒng)。
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(); }
上述代碼描述了一個開關(guān)事件的抽象類,和兩個繼承該抽象類的內(nèi)部類。這些內(nèi)部類能夠自由地訪問Test類中的字段,無需任何條件。
記得看?。。?/p> 10.9 內(nèi)部類的繼承
public class Test extends Outer.Inner { // 如果沒有下面的構(gòu)造方法會編譯失敗 public Test(Outer outer) { outer.super(); } } class Outer { class Inner {} }
可以看到Test只繼承了內(nèi)部類Inner,而不是外部類。
當(dāng)要生成一個構(gòu)造器時,必須要增加這樣一段代碼outer.super();
解釋:內(nèi)部類的構(gòu)造器必須連接到指向外部類對象的引用,而在內(nèi)部類的子類中不再存在可連接的默認(rèn)對象。所以需要在子類的構(gòu)造器中包含指向外部類的引用,必須是帶參數(shù)的,而且參數(shù)類型是外部類。說白了就是,內(nèi)部類的對象依賴外部類的對象,內(nèi)部類的子類的對象,也仍舊是依賴外部類的對象的。
10.10 內(nèi)部類可以被覆蓋嗎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中的方法,當(dāng)構(gòu)造器調(diào)用setInner(new Inner());的時候,是把Test.Inner向上轉(zhuǎn)型為Outer中的引用inner。
10.11 局部內(nèi)部類(見10.5)
前面提到過,可以在代碼塊里創(chuàng)建內(nèi)部類,典型的方式是在方法體內(nèi)。
局部內(nèi)部類不能有訪問說明符,因為他不是外部類的一部分。
局部內(nèi)部類可以訪問當(dāng)前代碼塊內(nèi)的常量,以及此外圍類的成員。
局部內(nèi)部類可以有構(gòu)造器以及重載構(gòu)造器,而匿名內(nèi)部類只能用于實例初始化。
局部內(nèi)部類可以創(chuàng)建多個對象,而匿名內(nèi)部類最多有一個
10.12 內(nèi)部類標(biāo)識符每個類都會產(chǎn)生一個.class文件,其中包含了如何創(chuàng)建該類的對象的全部信息(此信息產(chǎn)生一個“meta-class”,叫做Class;對象),內(nèi)部類也是如此。
外部類的名字:外部類名.class
普通內(nèi)部類:外部類名$內(nèi)部類名.class
匿名內(nèi)部類:外部類名$編譯器分配的數(shù)字.class
多層嵌套:按從外到內(nèi)用$分割.class
對于Unix shell而言,$是一個元字符,所以在列出.class文件的時候,有時會有問題。
10.13 總結(jié)內(nèi)部類涉及內(nèi)容相對復(fù)雜,多花點時間吧~
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/72196.html
摘要:抽象類和抽象方法抽象方法這種方法是不完整的,僅有聲明而沒有方法。創(chuàng)建抽象類和抽象方法非常有用,因為他們可以使累的抽象性明確起來,并告訴用戶和編譯器打算怎樣來使用它們。接口用于建立類于類之間的協(xié)議。與抽象類相同,防止客戶端程序員創(chuàng)建該類對象。 點擊進入我的博客 接口和內(nèi)部類為我們提供了一種將接口與實現(xiàn)分離的更加結(jié)構(gòu)化的方法。 9.1抽象類和抽象方法 抽象方法:這種方法是不完整的,僅有...
摘要:方法的基本組成包括名稱參數(shù)返回值方法體方法名和參數(shù)列表唯一的標(biāo)識出某個方法。如果返回的類型是,則的作用僅是退出方法否則必須返回正確的返回值包名名字可見性約定以域名反轉(zhuǎn)作為包名,用來劃分子目錄,并且全部小寫。 點擊進入我的博客 2.1用引用操縱對象 盡管一切都看作對象,但操縱的標(biāo)識符實際上是對象的一個引用。 String s; // s是一個String類型的引用, 并沒有任何對象與其...
摘要:在設(shè)計模式中,所有的設(shè)計模式都遵循這一原則。其實就是說在應(yīng)用程序中,所有的類如果使用或依賴于其他的類,則應(yīng)該依賴這些其他類的抽象類,而不是這些其他類的具體類。使用設(shè)計模式是為了可重用代碼讓代碼更容易被他人理解保證代碼可靠性。 這是劉意老師的JAVA基礎(chǔ)教程的筆記講的賊好,附上傳送門 傳智風(fēng)清揚-超全面的Java基礎(chǔ) 一、面向?qū)ο笏枷朐O(shè)計原則 1.單一職責(zé)原則 其實就是開發(fā)人員經(jīng)常說的高...
摘要:類最基本的作用,在于通過類獲取到相應(yīng)的對象,在向?qū)ο蟀l(fā)送消息時以期望對象做某些特定的事情。先導(dǎo)概念引用中一切皆對象,因此采用一個指向?qū)ο蟮囊脕聿倏v對象。對象可以存活于作用域之外。 歡迎各位讀者關(guān)注我的微信公眾號,共同探討Java相關(guān)技術(shù)。生命不止,學(xué)習(xí)不休! showImg(https://segmentfault.com/img/bVboaBO?w=129&h=129); 也許你慢...
摘要:包命名規(guī)范使用小寫字母。包訪問權(quán)限為把類聚在一個包中的做法提供了意義和理由。接口訪問權(quán)限使用關(guān)鍵字,意味著被它修飾的成員對所有類可見。繼承訪問權(quán)限基類的創(chuàng)建者希望某些特定成員,把它的訪問權(quán)限賦予派生類也不是所有類。 點擊進入我的博客 6.1包:庫單元 import java.util.ArrayList; import java.util.*; 當(dāng)編寫一個Java源代碼文件(編譯單...
閱讀 1204·2021-11-15 18:00
閱讀 1799·2021-10-08 10:15
閱讀 763·2021-09-04 16:48
閱讀 2389·2021-09-04 16:48
閱讀 1322·2019-08-29 18:40
閱讀 976·2019-08-29 13:08
閱讀 2997·2019-08-26 14:06
閱讀 1119·2019-08-26 13:35