极*Java速成教程 - (4)
Java語言基礎
多態
多態是面向對象的一大重要特性,如果說封裝是隱藏一個類怎么做,繼承是確定一系列的類做什么,那多態就是通過手段去分離做什么和怎么做。
向上轉型與收窄
在開發者將一類事物封裝成類以后,他們的具體操作都被隱藏,而通過繼承獲得的“特化”的子類,滿足了父類全部的性質,也就是說子類也是一種擴大的父類,子類比父類多了點東西。
那么以對父類的要求去要求子類,子類自然也全部符合要求,也就是說,可以用子類變量填充父類參數列表,用子類對象調用父類public方法,重寫方法返回父類方法返回類的子類,這時候把子類的帶有特性的東西丟出去一些就好,“給”的時候宜多不宜少。
我們不用關心操作的是子類還是父類,只要這個對象可以調用繼承樹根中的某一個類定義的方法就好。
向下轉型與報錯
如果把子類給了父類,就是多給了東西,Java編譯器回把多余的丟掉,但是如果少給了東西,把父類給了子類,就會出現父類缺少子類特性的問題,就會不夠用,就可能會報錯。
綁定
將一個方法的調用和方法的主題關聯起來叫做“綁定”,程序設計中,綁定分為兩種,一種是當代碼編譯時就將方法調用和主體關聯起來,叫做前期綁定,一種是運行起來以后才將方法調用和主體關聯起來,叫做動態綁定。
動態綁定就像是有一個樂器演奏列表,列表中的每個樂器都要被演奏,對于程序來說,不知道下一個進來的是小提琴還是手風琴,但是只要是樂器(父類),樂器有演奏的方法,程序就能進行各種具體樂器(子類)和演奏的關聯,然后對子類對象調用父類方法,就能正常運行(但是實際上運行的是子類從父類繼承來的,可能進行了重寫的方法)。
因此,我們應更關心類的設計,抽象出更合適的父類和繼承關系結構,才能減少代碼量,方便開發。
雖然Java絕大多數情況都是動態綁定,但final和static修飾的成員是靜態綁定的,這是他們“最終”和“面向類的靜態”的性質所決定的
接口
抽象類
就像小提琴和小號都是樂器,是樂器父類的子類,樂器父類具有演奏方法,子類自然也有。但是這時候就會出現一種問題,小提琴的演奏是拉的,小號的演奏是吹的,他們的演奏完全是不同的方法,那么父類定義的演奏方法有什么意義呢,是沒有意義,是一種純粹的抽象,基于這種思想,我們可以將父類中的演奏方法定義為抽象方法,用abstract關鍵詞修飾,只有方法的聲明而沒有方法體,沒有具體實現。有抽象方法的類就成了抽象類,抽象類不可以生成對象,繼承抽象類的類如果沒有實現方法體,那么也是一個抽象類,這個抽象的概念會傳遞繼承。
接口類
接口類是一種特殊的類,用interface關鍵詞替代了類的class關鍵詞。接口類中的所有方法都是抽象的,是只有方法聲明沒有方法實現的,其他類可以使用implements繼承接口類,繼承了接口類的子類必須實現接口類聲明的各個方法。
接口類中的屬性是默認final和static的。
通過繼承多個接口類,子類可以實現多重繼承,也就是子類滿足所有父類的基本要求,同時是多個父類的特例,滿足多個父類的要求,實現多種向上轉型。
接口類也是類,符合類繼承的一切規律。
接口的強大之處在于,對于任意的一個類,只要繼承了接口并實現了方法,那就滿足接口的一切要求。接口就像翅膀,插在任何能提供動力的物體上,通過實現具體的飛的方法,那么這個東西就可以飛。
還可以進行工廠模式的設計,用接口構建好類和工廠類,用工廠類接口方法返回類接口;然后使用具體的類對類和工廠進行實現,就可以實現工廠的效果,對工廠的不同“產品”執行相同的操作。
內部類
將一個類置于另一個類中,那這就是內部類。內部類從邏輯思想上來說,就像你需要設計一個汽車齒輪箱,你有所有基本的材料,但仍然需要自己敲打出來一些趁手的小部件才能完成組裝,這些定義在某個結構內部的類就叫內部類,內部包括類內部和方法內部等,受作用域限制。
內部類在類的內部完成定義,如果要創建一個內部類的對象,那么可以使用外部類對象.new語法在外部創建內部類對象,除靜態方法外,其實例化產生對象需要使用外部類.內部類的方法進行類型指明。。
定義在內部的類,擁有其外圍類所有成員的訪問權,可以使用外圍類.this獲取一個外圍類的引用。多層嵌套的內部類可以訪問其所有層次的外圍類的所有成員
通過使用訪問控制的內部類繼承接口,可以將接口實現并達到隱藏具體實現的效果,達到接口不可擴展的目的。
匿名內部類
匿名內部類就是一個沒有自己名稱的、繼承自另一個(抽象/接口)類的類,一般直接定義在return等地方并直接創建對象,可以簡化代碼。
匿名類沒有構造器(名字都沒有,怎么定義同名的構造器XD),匿名類的初始化,可以使用代碼段的方式進行{code},就仿佛是一個沒有名字沒有返回值的方法。當父類有有參構造器時,可以在匿名類參數列表括號里添加參數,將自動傳遞至父類。
匿名內部類中如果要使用外部定義的對象,那么需要是final的,但是匿名類的父類使用的對象不必是final的。
嵌套類
嵌套類就是static的內部類。嵌套類是類層次,而不是像其他內部類是對象層次的,創建嵌套類不需要外圍類的對象。
嵌套類具有和其他static成員類似的性質,且只能訪問static的外圍類對象,沒有外圍類的this指針。
嵌套類可以放在接口內部,甚至可以在內部類中實現外圍接口。可以方便地創造被所有接口實現類所共用的代碼。
內部類的應用
內部類可以獨立地承載接口,實現接口的功能,還不會讓這個接口的實現“污染”到外圍類的結構。內部類還可以針對同一個接口,實現不同的實現,可以豐富類的功能,比如一個類實現了一個迭代器接口,如果采取外圍類直接繼承接口的方式實現,那只能實現一種迭代,如果采取多個內部類實現同一個接口,那么就能實現多種迭代效果,比如反向迭代等。還可以使用內部類繼承一個完整的類,這就繞開了Java單根繼承的問題,可以構造更加復雜的多重繼承。
通過內部類,可以實現閉包的功能。通過將具體實現隱藏到內部類中,然后提供回調的接口將內部類暴露出來,就可以實現回調的功能。
通過內部類,可以實現控制框架等框架功能,就像是一個表示事物的類中通過內部類繼承事件類,實現了多種不同的行為,然后將實現了行為的內部類注冊到控制器中,通過控制器調用內部類運行功能。
內部類的繼承
如果只繼承內部類而不繼承外圍類,那么內部類的繼承需要在內部類的構造器中顯式地指明其依附的外部類對象,并調用外圍類.super()方法,在創建對象時提供相應的變量參數。
內部類不存在覆蓋的思想,父類和子類的內部類是完全隔離的。
方法內部的類
不能使用訪問控制關鍵詞,有作用域限制,與匿名內部類相比,局部內部類可以有多個對象,并且可以有命名的可重載的構造器可以使用。
異常處理
Java中的異常,就是“意料之中的錯誤”,當問題出現時,程序應該停下來,如果可以做就做一些處理,做不了處理就交給別人處理,而不是讓程序崩潰,因此異常可以增強程序的健壯性,對于一些可能發生的錯誤,有了更好的處理方式。System.err是標準錯誤流,可以打印出一些錯誤信息。
如何處理異常
首先,嘗試運行程序
try{
A
}
對于Java來說,try關鍵詞修飾的代碼塊是嘗試運行的,因為開發者知道,這里可能會出現問題。
然后,發現異常
對于Java來說,當發現可能出錯的問題的時候,比如嘗試訪問一個空的引用,那么就可以通過throw關鍵詞拋出異常,或者是在函數上通過throws關鍵詞聲明這個方法中可能向調用者拋出的異常。通過這種方法提出這個異常,交由外界進行處理避免程序的崩潰。
Exception類是所有異常類的父類,所有的異常都是Exception。
try{
throw new NullPointerException("a==null");
}
public void f() throws Exception{
throw new Exception();
}
標準Exception類都有兩個構造器,一個默認構造器和一個參數構造器,可以隨異常信息返回一個字符串供處理。可以自定義異常類型,繼承并實現Exception類。
如果throw句沒有包括在try中或者是沒有catch語句可以處理或者是catch語句處理不了,依舊可以用throw語句將錯誤對象拋出,拋給上一級的方法和對象,逐級上拋直至有對象能處理或者是程序崩潰,甩鍋嘛。
Java中異常的傳遞是一條甩鍋的鏈,從前甩到后,從里甩到外,從棧頂對象甩到棧底最后甩給jvm然后程序崩潰
解決異常
針對try中提出的問題,在catch代碼塊中進行匹配,與Type id2類型相同的異常會被代碼段B處理。
try{
throw new NullPointerException("a==null");
}catch(Type id1){
A
}catch(Type id2){
B
}
catch子句將匹配Type為基類的所有類(依舊是向上轉型原則),可以將捕獲Exception類的catch代碼放到最后,就可以捕獲所有的異常還不至于所有的異常都被其一網打盡。
可以使用Exception類中的initCause()方法,將前面發生的異常現場保存下來并加入自己的一些信息,最后形成一條異常鏈。
結束戰斗
當異常沒有catch代碼段能夠捕獲或者是異常處理結束時,可能還需要做一些收尾工作,那就交由finally代碼段處理。
try{
throw new NullPointerException("a==null");
}catch(Type id1){
A
}catch(Type id2){
B
}finally{
C
}
只要執行到了try代碼段,無論是否發生異常,異常是否被處理,只要虛擬機沒崩,finally代碼段將始終被執行。
因此,異常處理應遵循一個原則“在創建需要清理的對象后,立即進入一個try-finally語句塊”。
異常日志
可以使用java.util.logging工具將輸出記錄到日志中。常見的用法是通過Logger.getLogger(String)獲取靜態logger對象,然后使用靜態方法調用logger.severe(String)記錄錯誤日志。
異常的限制
在覆蓋方法時,只能拋出基類方法的異常列表中列出的異常,因為要保證向上轉型的正確性(兼容性?),否則如果出現了新的異常,基類將難以處理。
總結
以上是生活随笔為你收集整理的极*Java速成教程 - (4)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Hotspot的栈
- 下一篇: js 获取select的值