您好,登錄后才能下訂單哦!
Java內(nèi)部類真的很難理解,但有必要搞懂,因為內(nèi)部類讓外部類更豐富多彩了,就好像一個人的心中還可以住著另外一個人。
昨天晚上,我把車停好以后就回家了。回家后才發(fā)現(xiàn)手機落在車里面了,但外面太冷,冷到骨頭都能感受到寒意——實在是不想返回一趟去取了(小區(qū)的安保還不錯,不用擔(dān)心被砸車玻璃),于是打定主意過幾個小時的“世外桃源”生活——別人找不到我,我也找不到別人,這種與世隔絕的狀態(tài)非常適合讀書寫作。
把厚厚的《Java編程思想》擺在桌子上,正襟危坐,認認真真地讀起了第十章——內(nèi)部類。盡管我已經(jīng)非常耐心和用心了,但內(nèi)部類的這一章非常的枯燥,并且難以理解,我整個人幾乎處于崩潰的邊緣。
很早之前,有想要轉(zhuǎn)行學(xué)習(xí)Java的朋友咨詢我,有哪方面的書可以推薦,我鄭重其事地介紹了《Java編程思想》,并且一再叮囑他這是一本Java入門級的經(jīng)典書,必須耐著性子讀完它?,F(xiàn)在想想,自己當(dāng)時的推薦真是輕率!
我這樣說,并不是為了否認《Java編程思想》這本書的價值,因為站在書本的角度,它可能會感慨說:這王二的學(xué)習(xí)能力有問題啊,讀我竟然這么困難!
不是有那樣一句話嘛:“如果你手里有一把錘子,所有東西看上去都像釘子?!蔽艺J為“內(nèi)部類”這一章很難懂,其根本的原因在于我對“內(nèi)部類”沒有很好的理解。想要繼續(xù)扎實Java的基礎(chǔ)知識,唯一要做的就是——想盡一切辦法搞懂“內(nèi)部類”,并梳理成文。
顧名思義,內(nèi)部類就是放在另外一個類的內(nèi)部定義的類。非常重要的一點是,內(nèi)部類能夠訪問外部類的所有成員,包括private
修飾的。
來看程序清單1-1:
public?class?Wanger?{
????private?int?age;
????public?Wanger(int?age)?{
????????this.age?=?age;
????}
????class?Thought?{
????????public?void?know()?{
????????????System.out.println("沉默王二的年齡"?+?age);
????????}
????}
????public?Thought?getThought()?{
????????return?new?Thought();
????}
????public?static?void?main(String[]?args)?{
????????Wanger?wanger?=?new?Wanger(29);
????????Wanger.Thought?thought?=?wanger.getThought();
????????thought.know();?//?輸出:沉默王二的年齡29
????????//?使用.new的形式創(chuàng)建內(nèi)部類對象
????????Wanger.Thought?thought1?=?wanger.new?Thought();
????????thought1.know();
????}
}
程序清單1-1要表達什么意思呢?
答案是:我,沉默王二,已經(jīng)29歲了,89年出生(有人說89年出生明明是30歲)。上了年紀了,總想裝點嫩,理解一下。我讀書不多,但特別愛思考,于是我就給自己創(chuàng)建了一個會思考的內(nèi)部類Thought。
從程序清單1-1可以看得出,盡管Thought是內(nèi)部類,但可以訪問外部類Wanger的私有成員變量age。
如果想創(chuàng)建內(nèi)部類的對象,需要先指明對象引用的類型,格式為 OuterClassName.InnerClassName
,就像main()方法中的Wanger.Thought
那樣。
緊接著,就要來創(chuàng)建內(nèi)部類對象了,有兩種形式。第一種形式是先在外部類中定義一個方法Thought getThought()
,返回使用new
關(guān)鍵字創(chuàng)建的內(nèi)部類對象,然后使用外部類對象調(diào)用該方法wanger.getThought()
;第二種形式是直接通過外部類對象.new
創(chuàng)建wanger.new Thought()
。
以我的編程經(jīng)驗來看,匿名內(nèi)部類使用最頻繁的場合就是在創(chuàng)建線程的時候。
來看程序清單2-1:
public?class?Demo?{
????public?void?test(String?title)?{
????????Thread?thread?=?new?Thread(new?Runnable()?{
????????????@Override
????????????public?void?run()?{
????????????????//?title?=?"我不要吃雞";
????????????????//?改變時會提示錯誤
????????????????//?在封閉范圍中定義的局部變量必須是final的。
????????????????System.out.println(title);
????????????}
????????});
????????thread.start();
????}
????public?static?void?main(String[]?args)?{
????????for?(int?i?=?0;?i?<?10;?i++)?{
????????????Demo?demo?=?new?Demo();
????????????demo.test("我要吃雞"?+?i);
????????}
????}
}
在程序清單2-1中,test()方法內(nèi)部有一個線程對象thread,是通過new Thread()創(chuàng)建的。new Thread()
可以接收一個實現(xiàn)了Runnable接口類型的對象,這個對象要怎么創(chuàng)建呢?可以通過匿名內(nèi)部類的形式來創(chuàng)建——new Runnable() {public void run(){......}}
——這段簡短的代碼等同于:
//?實現(xiàn)Runnable接口
class?MyRunnable?implements?Runnable?{
????@Override
????public?void?run()?{
????}
}
//?向上轉(zhuǎn)型
Runnable?myRunnable?=?new?MyRunnable();
匿名內(nèi)部類的好處就在于不僅節(jié)省了定義實現(xiàn)類的過程,還能夠自動向上轉(zhuǎn)型。
在程序清單2-1中,test()方法還有一個參數(shù)title,JDK1.8之前,編譯器要求它必須是final類型的。但JDK1.8之后,如果我們在匿名內(nèi)部類中需要訪問局部變量,那么這個局部變量不再需要用final
關(guān)鍵字修飾了。
但如果想要在匿名內(nèi)部類中改變局部變量的值,編譯器就會提醒你不能這樣做,它會提示:“在封閉范圍中定義的局部變量必須是final的。”
Java的內(nèi)部類讓我很容易的想起來JavaScript的閉包,閉包就是定義在一個函數(shù)內(nèi)部的函數(shù)——這聽起來和Java的內(nèi)部類定義一樣一樣的。本質(zhì)上,閉包是將函數(shù)內(nèi)部與函數(shù)外部連接起來的橋梁。內(nèi)部類一樣,它是將內(nèi)部類與外部類連接起來的橋梁。
來看看什么是閉包吧:
function?wanger()?{
????var?age?=?30;
????function?know()?{
????????console.log(age);
????}
}
wanger();
//?控制臺輸出30
除此之外,內(nèi)部類最引人注意的原因是:
內(nèi)部類可以獨立地繼承一個抽象類或者實現(xiàn)一個接口,無論外部類是否也這樣做了,對內(nèi)部類都沒有影響。
上一篇:Java代碼復(fù)用的三種常用方式:繼承、組合和代理
下一篇:Java String,看這篇就夠了
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。