1. 程式人生 > >《Head First Java》

《Head First Java》

《HEAD FIRST JAVA》第一次回顧和整理

第一章 進入Java的世界(基本概念)

主要介紹了Java的工作原理,發展簡史,程式結構和一些簡單的語法。學過其他語言的人表示這章完全沒有壓力。 1,程式的層次:原始檔(source file)->類(class)->方法(methods)。 2,Java裡面integer和boolean不相容。 3,語法與C差不多

第二章 拜訪物件村(類與物件)

一開始用了一個巨冷的故事來闡述面向過程程式設計與面向物件程式設計的差別。 1, 繼承機制使子類可以通過繼承父類程式碼來減少重複程式碼,覆蓋機制使子類在不必改動父類的同時可以選擇實現自己的方法。 2, 類是繪製物件的藍圖,而物件是已知的事物加上執行的動作。對應著,類包括例項變數(instance variable)和方法(methods)。 3, Java程式執行期間是一組可以相互呼叫或交流資訊的物件,物件之間有著獨立性(物件自治)。 4, main()在java裡面的作用:測試真正的類和啟動Java應用程式。Java是面向物件的程式設計,所以main()裡面基本是不帶任何方法的,僅作為測試用和啟動用。

第三章 認識變數(primitive主資料型別和引用)

介紹了primitive型別變數和引用變數,並闡述了之前的差別。 1, 變數必須有變數型別,兩性型別與類之間有時是共通的,所以一般有著相同的命名規則(如果可能的話,每個單詞的首字母都要大些,區分於變數名稱的命名:除了第一個單詞首字母要小寫外,之後的單詞的首字母都要大寫)。 2, 變數名稱必須以字母,_或&開頭(不能以數字開頭)。 3, 除非加上“f”,否則所有帶小數點的值在Java裡面都看作double型別。 4, Primitive主資料型別變數值是該值的位元組所表示的。 5, 引用變數類似於指標,儲存的是引用物件的地址(儲存方式)。 6, 圓點運算子(.)表示“取得圓點前面的物件,然後求出該物件在圓點後面的事物”。 7, 當一個物件失去所有的引用變數時,它就完蛋了。 8, 陣列是物件,無論它裡面裝的是不是primitive型別。

第四章 物件的行為(方法操作例項變數)

這章主要是圍繞物件的方法來闡述一些拓展技巧。 1, 根據傳入的實參(arguments)或者物件的例項變數(instance variable)的不同,同一個方法在同類型的不同的物件可以有著不同的表現形式。 2, 實參(arguments)是傳給方法的實際值,傳入方法後就變成了形參。形參(parameters)與區域性變數(local)類似是一樣的。改變形參並不改變實參。(跟C一樣)傳入與返回的引數的值的型別可以隱含地放大或者明確地縮小。 3, 可以從方法裡面返回值,聲明瞭返回最好要返回,一般情況下只能返回一個值,但是可以返回一個數組,再深一層的,可以返回ArrayList,換言之,只要你封裝好了,可以返回任意數量任意型別的任意變數的任意組合。 4, Java是傳值呼叫(pass by value),如果呼叫的實參是個引用變數,同樣拷貝之。 5, 用setter(mutator)和getter(accessor)進行封裝(encapsulation),可以保證物件的例項變數可以通過設定setter來防止被惡搞。(用private設定例項變數,用public來設定setter和getter)這樣讀取和更改例項變數的效率會變低,不過能夠提高程式的抵抗力抗性和恢復力抗性。 6, 例項變數有預設值(整形為0,浮點型為0.0,布林型為false),區域性變數沒有預設值,使用前需要初始化。 7, 使用==來比較兩個primitive主資料型別或者兩個引用是否引用到同一個物件。使用equals()來判斷兩個物件是否在意義上相等。(關於“在意義上”的概念需要斟酌,目前主要用於比較String型別是否相等)。

第五章 超強力方法(編寫程式)

通過設計一個SimpleDotComGame大致地說明了程式設計與實現的步驟。 1, 程式設計的第一步是高層設計,把程式的基本架構抽象出來。 2, 第二步,根據基本架構來構思需要什麼物件,需要實現什麼類。(這是與面向過程不一樣的地方,但某程度上類的方法有點像面向過程中的過程函式的一部分,Java優勝在那強大的類的獨立性)。書本上提議開發類的過程是:找出類應該做的事情->列出例項變數和方法->編寫方法的虛擬碼->編寫方法的測試用程式->實現類->測試方法->出錯或重新設計->邀請辣妹參加慶功派對 3, 偽碼,描述要做什麼而不是怎麼做的類文字。測試碼,寫在真實碼之前(因為真實碼都寫出來了估計就沒動力寫測試碼了),目的是為了寫好真實碼之後測試真實碼。 4, 書本後面介紹了幾個技巧:加強版的for(要先把環境引數調到1.5以上才能用);把字串轉換成整形的Integer.parseInt(String);還有C裡面學習過的後遞增和break語句。

第六章 使用Java函式庫 (認識Java的API)

這章的頁數很多,把第五章的遊戲排BUG之後又升級到高階版(依然無介面)。之後介紹了Java API的用途和用法。 1,排BUG過程中書本引入了強大ArrayList物件,這個物件很牛地,有著類似陣列的簡易操作性的同時有著類似連結串列的動態伸縮性,代價是它耗費的資源多一點。(對於add(index, Object)這個方法,index的值與之前的值不能跳空) 2,製作高階版時,書本用一堆球和杯子加遙控器的組合強調了Java是個面向物件的程式設計工具。 3,接著寫到了一些布林表示式的運算子,跟C一樣,所以沒有壓力。 4, Java API中類是被包裝在包中的;使用是必須使用import或者在出現的每個位置寫出全稱(除了java.lang包中的類);關於java和javax的趣聞;關於查詢API給出了查閱參考書和查閱HTML API文件(真希望能具體點)。

第七章 物件村的優質生活(繼承與多型)

1, 關於方法的繼承(inheritance)與覆蓋(override),書上說得是很清楚的,子類可以繼承父類所有的非私有方法,也可以通過寫出同名同參數的方法來覆蓋父類的方法。方法呼叫時,遵循低階優先原則。關於方法繼承,有一點要分辨清楚的,子類繼承了父類的方法,與把父類的方法的程式碼拷貝一份到子類的程式碼中的意義是不一樣的,當其他物件引用該方法時,前者會跳入父類中進行呼叫,後者會跳入子類中進行呼叫(因為方法已經被覆蓋了)。兩者的主要差別是如果兩者有著同名的例項變數,方法中又涉及了該例項變數,就會產生不同的結果。即使它們共用同一個例項變數,這點上的模糊也通常會導致方法返回一個跟預想不一樣的值或者產生一個預料未及的結果。 2, 設計繼承樹的步驟:找出具有共同屬性和行為的物件(用繼承來防止子類中出現重複的程式程式碼)->設計代表共同狀態與行為的類 ->決定子類時候需要讓某項行為(也就是方法的實現)有著特定不同的運作方式->通過尋找使用共同行為的子類來找出更多抽象化的機會->完成類的繼承層次。 3, 判斷選擇繼承還是看作例項變數的方法:“是一個”(IS-A)和“有一個”(HAS-A)。 4, 一些關於方法繼承的細節:繼承單向性(因而有了IS-A的單向性),父類無法繼承子類的方法;子類中可以用super()來引用父類的方法;public型別的成員會被繼承,private型別的成員不會被繼承;x extends y && y extends z —> x extends z,就是說,x可以通過z的IS-A測試;繼承可以減少重複程式碼,當要修改方法時,只要父類的引數沒有改變,子類都不需要改動就能直接繼承;繼承定義出共同的協議,也就是說,繼承可以確保某個父類之下所有子類都會有父類所持有的全部可繼承方法;可以用final來標記類使它或者把裡面的例項變數和方法標記成private來拒絕被繼承;在不知道父類原始碼僅知道其方法關鍵字的時候,可以通過繼承的方法來設計功能有所延展的子類。 5, 多型(polymorphism):當定義一組類的父型時,可以用子型的任何類來填補任何需要或期待父型的位置。換句話說,運用多型時,引用型別可以是實際物件型別的父類,這樣的話,引數和返回型別都可以多型化處理。其中有一點是要特別注意的,當一個物件實質是子類但它的引用物件是子類的父類時,雖然它本質是子類但它卻不能呼叫子類中的任何東西,Java看重的是引用型別,也就是說此物件只能引用父型中的東西,但可以通過用子類的強制轉換符來把引用轉換成子類。 6, 最後談談覆蓋和過載,子類同名方法未必就能覆蓋掉父類的方法:連引數型別和數目都相同時叫覆蓋,稍有不同就叫過載。過載之間毫無聯絡,各自獨立存在,JVM會根據引數的差別自行決定呼叫哪個過載的方法。最後是關於覆蓋和過載的一些細節上的區分:覆蓋(override),引數必須要一樣,其返回型別必須要相容;不能降低方法的存取許可權。過載(overload),返回型別可以不同;不能只改變返回型別(引數在型別和數目上至少要稍有不同);可以更改存取許可權(因為相互獨立)。

第八章 深入多型(介面與抽象類)

這章繼續討論多型,書上說沒有介面活不下去,現在有點體會。Java子類有時候扮演著不同的角色,這時候就需要用到介面了,因為父類只能有一個,但是介面的話就沒有這個限制了。 1,抽象類(abstract class):有一些類在理論上是不應該被初始化的,這時候加上abstract關鍵字可以防止它被new出來。抽象類的作用就是在防止被初始化之餘能被繼承以維持多型。。抽象類必須要被extends。 2,抽象的方法:抽象的方法沒有實體,因而一定要被覆蓋,即必須要實現所有抽象的方法。當聲明瞭一個抽象的方法時,該類必須標記成抽象類(我理解成這是要通過強迫設定子類繼承來實現方法的覆蓋)。 3,萬用類Object:所有類的父類;書上介紹的四個方法:equals(),hashCode(),getClass(),toString();Object的作用是為多型提供一個萬能模板,因而同樣要注意到Object型別的變數只能做Object類裡面的方法,要使用子類的方法,只能通過強制轉換符(再次強調Java很注重引用變數的型別:“編譯器是根據引用型別來判斷有哪些method可以呼叫,而不是根據Object確實的型別。”);而理所當然地,任何物件都可以使用Object裡面的方法。 4,書本再再再次強調了Java很注重引用變數的型別:只能在引用變數的類確實有該方法才能夠呼叫它;把類的公有方法當做是合約的內容,合約是你對其他程式的承諾協議。 5, 介面(interface):本質上是一個公用的且裡面都是抽象的方法的抽象類。目的是為了讓物件從單一的父子類關係中得到拓展以在保持物件獨立性和脈絡清晰性的同時得到多重身份。一言蔽之,介面就是為多型而存在的。介面可以跨越不同的繼承樹進行延展,同一物件也可以接上任意的介面。

第九章 物件的前世今生(構造器與垃圾收集器)

構造器(constructors)和垃圾收集器(garbage collection)。 1,關於生存空間和生存週期(life)和作用域(scope)什麼的,學過C的表示沒有壓力。所有的物件生存在堆(heap)中,方法呼叫和區域性變數生存在棧(stack)上,而例項變數是生存在其依附的物件上,即也屬於堆中。關於棧,遵循後進先出原則,關於各種引用變數,區域性引用變數存在於棧,例項引用變數存在於堆,儲存的自然只是存取方式。 2,建構函式(constructor):一項關鍵特徵是它不會有返回型別(包括void),另一項關鍵特徵是它會在物件能後被賦值給引用之前就執行。一些建構函式的應用細節:可以使用建構函式來初始化物件的例項變數,如果有提供預設值的要求,還可以通過過載建構函式來滿足,而且最後在無引數的建構函式中設定一個預設值;編譯器會幫你自動補全,前提是你沒有寫任何一個建構函式。 3,建構函式與父類之間的關係,這個確實有點糾結:由於子類都包含了父類的例項變數,所以當子類的繼承函式執行前,必須先執行父類的繼承函式,直至最後執行Object的建構函式,這個過程成為“建構函式鏈”(constructor chaining);呼叫父類的建構函式用super(),呼叫類中的過載建構函式用this(),而由於super()和this()語法上都要求放在建構函式的第一行,所以它們不能同時使用。 4,關於垃圾收集器的工作機理:當物件失去最後一個引用變數時,它失去存在的意義,等待的就是被回收的命運。關於引用變數的生存週期,區域性引用變數生存與方法當中,方法結束,引用就消失;例項引用變數的生存週期與它存在的類的生存週期一樣,換句話說,他倆的生死大權在類的引用變數上,死去的方法有“引用永久性的離開它的範圍”“引用被賦值到其他的物件中”“直接將引用設定為null”。

第十章 數字很重要(數字和靜態)

介紹完靜態之後就是一些對數字,格式化,日期等之流的介紹,大概瀏覽了下。 1, 靜態的方法通常是實用的方法,不依賴物件的例項變數(可理解成語句獨立性很強,不依賴前後的語句),因而不需要建立物件(並且通常建構函式私有化來阻止使用者建立例項)。引用時用類的名字來引用即可。又因為靜態方法引用物件的是類,所以靜態方法是不可及呼叫同一個類中的非靜態的例項變數(因為無法識別應該呼叫那個物件的的變數,類似的理由,靜態方法也不能呼叫同一個類中非靜態方法),只可以呼叫靜態例項變數(因為同類的物件共享同一個靜態例項物件,不存在混淆的問題) 2, 靜態變數具有共享的特性,在類被載入時初始化(優先於建構函式,並在所有靜態方法開始前初始化)。如果即將執行靜態方法前還沒有賦初值,自動設為預設值,整形為0,浮點型為0.0,布林型為false,引用變數為null。 3, Java中的常數:用public static final來修飾,即具有“公用”“免例項”“不變”的特性。 4, final:用於變數時,變數不可改變值(定義時貌似必須初始化);用於方法時,方法無法被覆蓋;用於類時,類無法被繼承。名副其實的終結者。(注:final的類沒必要再定義final的方法,無法繼承根本不存在方法被覆蓋的問題。) 5, primitive主資料型別的包裝:1.5之後有了自動包裝和解包(autoboxing),一切都變得很美好。基本可以無視int和Integer的差別了,直接套用就是了,強大無比的實。用性。(目前發現不可套用的是ArrayList中的contains方法,需要用到強制轉換符。)後面提到了包裝的實用性方法:parseInt(),parseDouble(),booleanValue(),toString()等。 6, 數字的格式化:學過C的表示繼續沒有壓力。 %[argument number][flags][width][.precision]type 這個寫得好專業就收錄下來了,其他看書OK。 7, 日期的表示法和計演算法:(import java.util.Date;import java.util.Calendar) 8, 最後一點,靜態的import,這個我覺得作用不大,為少翹一點程式碼而降低程式的易讀性很不划算。

第十一章 有風險的行為(異常處理)

開始介紹如何編寫軟體。這章主要說異常處理(exception handling)和MIDI(musical instrument digital interface)播放相關。 1, 異常處理:除了RuntimeException和它的子類(一般是可以在編譯階段排除的語法錯誤),其他異常(exception)都要進行處理(或者duck掉給呼叫者處理)。處理方法使用try{}和catch{}語句。(選擇性加上finally{},兩者至少要有一個。)如果不想在當前處理,可以用throws標識方法來duck給此方法的呼叫者,呼叫者也可以進一步duck給上一級呼叫者。如果連main()函式也ducking,那麼JVM就會死掉。一些細節:try的時候遇到異常後立即跳到catch(如果有的話),否則執行finally(如果有的話),之後丟擲錯誤(如果有throws字尾的話);一個try後面可以多個catch,平行關係的異常,可以不管先後順序,父子關係的異常,子型放在父型之上。 2, MIDI(import javax.sound.midi.*;):本身不帶有音樂資訊,上面帶的是如何播放音樂的資訊,跟樂譜差不多,所以佔用空間很小。播放音樂的層次:Sequencer(播放器)->Sequence(CD盤)->Track(單曲)->MidiEvent(音符)。構建的五個步驟:取得Sequencer並將它開啟->建立新的Sequence->從Sequence中建立新的Track->填入MidiEvent並讓Sequencer播放->按下play鍵。然後是各種的方法和各種的引數,各種看書和查閱JAVA API(MIDI的引數表至今沒有找到)。

第十二章 看圖說故事(圖形使用者介面)

這章主要介紹了GUI(Graphical User Interface):製作視窗和按鈕,簡單繪圖和貼圖,簡單的動畫等等。 1,JFrame用於建立主框架,通過getContentPane()把JButton,JLabel等其他元件(widget)掛載在上面。(import javax.swing.*;其他方法和引數見書本或JAVA API) 2,事件源(event source)本身是個物件(框架,按鈕,滾動條等),把使用者的操作(點選滑鼠,按鍵等)轉換成事件(event),如果當前事件源被一個或若干個監聽器(listener)註冊,那麼它會把事件(event object)當成引數返回到實現了對應的監聽介面的物件上面。 3, 通過用子類繼承JPanel來掛圖和繪圖。掛圖和繪圖在類裡面的paintComponent方法裡面實現。繪圖的時機一般由系統決定,也可以通過repaint()命令來強制馬上重繪。 4, 內部類(inner class):唯一繫結在第一個初始化自己的外部類上,繫結後不可更改繫結物件,可以使用外部所有的方法與變數,包括有私有標識的。 5, Thread.sleep()用於短暫掛起執行緒。(C裡面的Sleep()函式••) 6, 監聽MIDI檔案的方法:註冊一個特殊編號的MIDI事件(看作ControllerEvent)插入到MIDI檔案上所有含有NOTE ON(第一個引數是144)標誌的節拍上,把ControllerEventListener註冊到sequence上,最後在帶有ControllerEventListener()介面的controlChange(ShortMessage ev)方法上實現監聽後的響應工作。

第十三章 運用Swing(Swing)

篇幅比較短的一章,主要介紹了佈局管理器(Layout Managers)。 1, 幾乎所有元件(Components,或widget)都能夠安置其他的元件,除了JFrame之外,互動元件於背景元件的差異不明顯(JPanel雖然一般都當做背景來使用,但也可以像按鈕一樣註冊滑鼠點選的事件) 2, 佈局管理器(Layout Managers):通過一種互動的機制(人機互動,佈局層次內部的互動)自主決策元件佈局的一類物件。決策時優先遵循自己的佈局策略,在不破壞自身佈局策略的前提下最大程式上滿足使用者提出的佈局請求(也就是有時候會違反使用者的請求)。 3, 書上提到的三大布局管理器:BorderLayout(把背景元件分成東南西北中五個區域,優先分配南北,然後東西,最後剩下的部分為中間),FlowLayout(把元件從左到右地排列,並有自動換行的機制),BoxLayout(把元件從上到下地排列,但不帶有自動換行的機制) 4, 剩下的JTextArea,JScrollerPane等的方法和引數等可參看書本。

第十四章 儲存物件(序列化和檔案輸入/輸出)

1, Java資料輸出的兩種方法,只給Java讀取的話用序列化(serialization),如果要給其他程式讀取或使用,輸出純文字檔案。 2, (import java.io;)一般來說,串流(stream)要連線流(connection stream)和連結流(chain stream)兩兩配合才能有效。其中連線流負責連線到檔案,socket等,但因為自身一般只有像輸出位元組等低階方法,所以要藉助較為高階的連線流中的高階方法才能轉換成功。 3, 要一個類實現可序列化,需要實現Serializable介面。如果不想某個例項變數被序列化,標記上transient(像網路聯機這類隨機資料也應該標記transient),考慮到要完整且正確地恢復到原狀態(所謂狀態,一般就是指例項變數的值),序列化時候需要把與儲存物件相關的所有物件形成的網路全部序列化儲存(如果網路中有一部分例項變數既沒有實現Serializable又沒有被標記transient)。 4, 對於純檔案的處理用FileWriter和FileReader,為提高效率,可以選擇使用BufferedReader和BufferedWriter 5, 剩下還有關於GUI和IO的很多類很多方法很多引數,參看書本吧。

第十五章 網路聯機(網路與執行緒)

這章大致介紹了怎麼實現網路聯機,還是就是一些多執行緒的細節問題。 1, 聊天程式的工作方式:客戶端連線到伺服器->伺服器建立連線並把客戶端架到來並清單中->另外一個使用者連線上來->使用者A送出資訊到聊天伺服器上->伺服器將資訊送給所有的來賓。 2, Java不需要注意太多細節的東西就可以架設好網路連線。 3, (import java.net.*;)建立socket連線,要知道IP地址和TCP的埠號。(本機IP地址為:127.0.0.1) 4, 關於網路串流的讀寫:讀,伺服器(server)->Socket輸入流->InputStreamReader->BufferedReader->客戶端(client)。寫,客戶端->PrintWriter->Socket輸出流->伺服器。(不知道為什麼中間不加BufferedWriter) 5, 多執行緒(multithreading):執行緒(thread)是一種獨立的執行空間(a separate call stack),除非是多處理器,否則新執行緒並不是單獨執行的執行緒,雖然感覺上是這樣。 6, 每個thread需要一個任務來執行,一個可以放在執行空間的任務(實現Runnable介面的中的run(),類似於主執行緒的main()方法)。執行緒有“新建”“可執行”“執行中”三個狀態,而且,一旦執行緒進入了“可執行”狀態後,它會在“可執行”和“執行中”兩種狀態中不停地切換(除非處於堵塞狀態) 7, 執行緒排程器(the thread scheduler):Java自帶的決定什麼時候執行哪個執行緒的一種機制,不受使用者的API的控制,所以排程結果無法確定(不同的機器有著不同的執行過程,同一臺機器也會有著不同的執行過程)。 8, 可以用sleep()方法來影響排程器,不過作用效果一般沒有想象中要好。 9, 併發性問題(concurrency issue):當兩個或以上的執行緒存取單一物件的資料的時候,就有機會發生各種奇怪的錯誤。為了排除這類問題,使用synchronized(同步化過的)標誌物件執行中的那些不可分割的過程,類似於一把鎖,鎖住了儲存資料的方法,使一個物件對這個資料使用完畢之後再允許其他物件使用該資料。

第十六章 資料結構(集合和泛型)

各種集合(collections) 1, 各種資料結構:TreeSet(有序防重複),HashMap(每個資料都有對應的KEY值),LinkedList(大集合的快速插入和刪除中間元素,這效果,有點像連結串列),HashSet(防重複,可以快速尋找元素),LinkedHashMap(HashMap的升級版,具體看書)。書本的說法是:list對付順序結構,set注重獨一無二的性質,map用key來搜尋的專家。 2, 使用System.out.println集合的時候,要覆蓋集合元素的類中的public String toString()方法來設定輸出的內容。 3, 使用Collection.sort(某集合)方法的時候,要求某集合的元素實現排序化(實現Comparable介面之下的public int Compareto()方法),或者用sort的過載方法sort(某集合,某比較器),當然之前要現實某比較器(Comparator)中的int Compare()方法。 4, 關於泛型(generic):java5.0之後推出的功能,為了實現更好的型別安全性。一般用表示,對於集合,也用來表示(E for element),型別引數會被編譯器自動識別和替換或的位置。然後public void takeThing(ArrayList list)跟public void takeThing(ArrayList list)含義是不一樣的。還有,泛型裡面的extends和implements其實都是is的意思,但是創造新的關鍵字會破壞之前的程式,所以沒有引用is關鍵字。 5, 物件相等:包括引用相等性和物件相等性,前者指“堆上同一物件的兩個引用”,後者指“堆上的兩個不同物件在意義上是相同的”,一般需要的是後者,要實現後者,就必須覆蓋從Object繼承下來的hashCode()和equals()方法。以HashSet為例,檢查兩個變數是否相等,首先檢查hashCode()的返回是否一樣,然後再檢查equals()函式的返回是否是true。更加細節的東西:hashCode相同並不能保證物件相同的,因為hashCode使用的是雜湊演算法。還有就是覆蓋equals()方法是要注意它的引數是Object型別的。 6, TreeSet的元素必須實現Comparable或者在構造的時候用comparator來初始化。 7, 然後是多型的問題:不知出自什麼原因,java設計時設定陣列的型別檢查是在執行使其進行的,而集合的型別檢查只在編譯時期,所以多型在集合要實現要麻煩些——public void takeAnimal(ArrayList

第十七章 釋出程式(包,jar存檔檔案和部署)

檔案部署,打包成jar。 1, 部署分成:完全在本機的Executable Jar,完全在遠端的Servlets和介乎兩者之間的JWS。 2, 原始碼和類檔案的分離:原始碼放在source,類檔案放在classes,使用命令-d。 3, 打包JAR:首先,確認所有的類檔案都在classes目錄下,然後在該目錄下建立manifest.txt來指定哪個類帶有main()方法(Main-Class: ),最後用jar命令打包。(jar –cvmf manifest.txt .jar *.class) 4, 執行JAR:在cmd下用java –jar *.jar命令來啟動,如果自帶GUI,在windows環境下可以雙擊開啟。(若開啟是被winrar等程式干擾時,開啟方式設為jre/bin下的javaw.exe,然後在用regedit開啟登錄檔,在HKEY_CLASSES_ROOT下找到.jar檔案的開啟方法,在引數中間新增-jar字樣) 5, 包:主要用於防止類名稱的衝突,關於製作包執行包用包弄JAR等具體命令參看P589左右(懶人表示期待工具) 6, Java web start(JWS):書本介紹較為簡單,還夾雜著XML的語言…

第十八章 分散式計算(遠端部署的RMI)。

1, RMI(remote method invocation):一種連線客戶端和伺服器的技術(有點像socket)。事實上,在某堆上的物件無法進行另外堆上的物件引用,但是利用RMI能夠模擬這種感覺。實現需要四個部分:伺服器(server),客戶端(client),伺服器輔助設施(server helper),客戶端輔助設施(client helper)。客戶端呼叫客戶端輔助設施來模擬呼叫本機物件的感覺,而實際上客戶端輔助設施只是作為代理(proxy),真正實現客戶端請求的是伺服器。 2, RMI呼叫方法的過程:客戶端物件對輔助設定物件呼叫方法(已註冊的方法)->客戶端輔助設施把呼叫資訊打包通過網路送到伺服器的輔助設施->服務端的輔助設施解開來自客戶端輔助設施的資訊,並以此呼叫真正的服務。 3, 建立RMI遠端服務:步驟一:建立Remote介面(繼承java.rmi.Remote;生命所有的方法都會丟擲RemoteException;確定引數和返回值都是primitive主資料型別或者Serializable);步驟二:實現Remote(實現Remote這個介面;繼承UnicastRemoteObject;編寫宣告RemoteExceiption的無引數建構函式;向RMI registry註冊服務);步驟三:用rmic產生stub與skeleton(對實現出的類(不是Remote介面)執行rmic);步驟四:啟動RMI registry(調出命令列來啟動RMI registry);步驟五:啟動遠端服務(呼叫另一個命令列來啟動服務) 4, Servlet:servlet是完全放在HTTP WEB伺服器上執行的JAVA程式,用於應付使用者端沒有JAVA虛擬機器的情況。建立並執行servlet的步驟:找出可以存放servlet的地方(就是要買個伺服器);取得servlets.jar並新增到classpath上(上sun官網掛之);通過extend過HttpServlet來編寫servlet的類;編寫HTML來呼叫servlet(我不會••);給伺服器設定HTML的網頁和servlet。 5, JINI(Java Intelligent Network Infrastructure):傳說中一個更加強大的RMI,帶有自適應探索(adaptive discovery)和自恢復網路(self-healing networks)。因為很強大,所以書上也沒有篇幅去細說。後面是實現方法和一堆堆程式碼,看得我產生了嚴重的抵觸情緒。

以下是自己著重理解的部分,做了大量筆記。

一進入JAVA的世界

1java工作方式 原始碼 編譯器 編譯.java 輸出 .class位元組碼檔案 編譯後的位元組碼與平臺無關 Java虛擬機器 JVM 將位元組碼轉換成平臺能夠理解的形式 2java程式結構 main()是程式的起點 類存在於原始檔之中,方法存在與類中,語句存在於方法中 3剖析類 4main()方法 5迴圈 6條件分支 7設計程式 如果沒有類的宣告,程式就無法通過編譯 While迴圈必須在方法裡面

二拜訪物件

面向物件的適用性和可擴充套件性 不需改動之前已經測試好的程式程式碼

1椅子大戰

square circle triangle amoeba rotate palysound 面向過程與面向物件的思考 當你在設計類時,要記得物件是靠類的模型塑造出來的。把物件當做例項。 物件是已知的事物,物件本身已知的事物被稱為例項變數(instance variable) 物件會執行方法,物件可以被執行的方法被稱為方法。(methods) 類是物件的藍圖,它會告訴虛擬機器如何建立某種型別的物件。根據某類創建出的物件都會有自己的例項變數。 建立物件時,它會被存放在被稱為堆的記憶體區域中。是一個可回收垃圾的堆。 2繼承 3覆蓋 4類 5物件 6使用main() 7猜數字

三認識變數

1宣告變數

變數就像是杯子,是一種容器,承載某些事物。它有大小和型別。 你無法用小杯子裝大的值。可以,但是會溢位。 給變數賦值的方法:直接賦值,指派其他變數的值,以上兩種方式的組合

2primitive主資料型別

boolean char byte short int long float double

3java關鍵字

名稱:字母、數字、下劃線、美元符號 開頭:不能是數字

4引用變數

物件的宣告建立賦值: 1宣告一個引用變數2建立物件new3連線物件和引用 注意: 1事實上沒有物件變數這樣的東西存在 2只有引用到物件的變數 3物件引用變數儲存的是存取物件的方法 4它並不是物件的容器,而是類似指向物件的指標。或者可以說是地址。

5物件的宣告與賦值

6可回收堆空間

但是在JAVA中我們不會也不應該知道引用變數中實際裝載的是什麼,它只是用來代表單一的物件。只有JAVA虛擬機器才會知道如何使用引用來取得該物件。 你無法將物件裝進變數裡,並沒有巨型的杯子可以放大到能夠裝載所有的物件,物件只會存在於可回收垃圾的堆上。 物件引用也只是個變數值,還是會有東西放進杯子裡,只是引用所放進去的是遙控器。 物件若沒有引用,則變成了無法存取的,就會被垃圾回收機制回收。

7陣列

宣告int[] nums; 建立nums=new itn[7]; 賦值nums[0]=6; 陣列也是物件 陣列中的每個元素都是變數,會是主資料型別變數中的一種或者是引用變數。 宣告Dog[] pets; 建立pets=new Dog[7]; 賦值pets[0]=new Dog(); 訪問不需要使用變數名稱,只需要陣列索引位置就可以操作特定物件

四物件的行為

1操作物件狀態的方法

每個物件都有獨立的例項變數值 每個物件都帶有相同的方法,但是方法可以根據例項變數的值來表現不同的行為。

2方法引數與返回型別

方法會呼叫形參,呼叫的一方會傳入實參。你可以傳值給方法。 你可以從方法中取返回值。 你可以向方法中傳入一個以上的引數。你可以將變數當做引數傳入,只要型別相符就可。

3值傳遞

int x=7; 宣告一個變數x賦值為7 void go(int z){ 宣告一個有參方法,引數名稱為z z=0; 在方法中,改變z的值 } foo.go(x); 此時,x的值不會被改變 。因為傳遞給z的只是個貝。 方法無法改變呼叫方法所傳入的引數。

4getters和setters

看過引數與返回型別的工作 Getter:返回例項變數的值 Setter:取用一個引數來設定例項變數的值

5封裝

資料隱藏:通過公有和私有兩種存取修飾符 將你的例項變數標記為私有的,並提供公有的getter和setter來控制存取動作。

6陣列中的行為

例項變數永遠都會有預設值。如果你沒有明確的賦值給例項變數,或者沒有呼叫setter,例項變數還是會有值。 Integers 0 floating points 0.0 booleans false references null 例項變數與區域性變數之間的差別。 1例項變數是宣告在類內而不是方法中 2區域性變數時宣告在方法中的 3區域性變數在使用前必須初始化(因為區域性變數沒有預設值,否則無法編譯) 那方法的引數呢?區域性變數規則也適用於它們身上 變數的比較 主資料型別、引用變數 ==判斷是否引用同一個物件 兩個物件是否真的相等 equals() 兩個物件吧是否在意義上相等

五超強力方法

1建立戰艦遊戲 2簡單版 3編碼 4測試 5程式 6完成版 7隨機數 8輸入 9迴圈 for(int i=0;i<100;i++)建立i,i小於0 就重複,每趟重複後i+1 for(string name:nameArray)建立變數,將後面的第一個元素賦值給name,執行重複內容,賦值 給下一個元素name,重複執行至所有元素都被執行為止 10型別轉換 11轉換字串

六使用JAVA函式庫

如果你知道如何從統稱JAVA API的java函式庫中尋找到所需要的功能,那麼就不用重新發明輪子了。 核心java函式庫是由一堆等著被你當做元件使用的類集合而成的,你可以大量運用這些預先建立好的元件來寫出你的程式。 1分析bug 2arraylist 比較 arraylist與一般陣列 1一般陣列在建立時就必須確定大小 String[] mylist=new String[2]; ArrayList mylist=new ArrayList(); 2存放物件給一般陣列時必須指定位置,必須要指定介於0~length-1之間的數字 如果索引值超越了陣列的限制,程式會在執行期出現錯誤 使用ArrayList,你可以使用add(int object)來指定索引值,或者使用add(object)給它自行管理大小 String a=new String(“wqw”); mylist[0]=a; String a=new String(“wqw”);mylisy.add(a); 3修改 4設計 5虛擬碼 6程式 7布林表示式 8api 9包

七物件村的優質生活

1繼承

子類繼承父類,子類會自動的繼承父類的例項變數和方法,但是子類也可以加入自己的方法和例項變數,也可以覆蓋掉繼承自父類的方法,但例項變數不能被覆蓋掉。 2設計繼承層次 3運用繼承避免重複的程式程式碼 1找出具有共同屬性和行為的物件 2設計代表共同狀態與行為的類 3決定子類是否需要讓某項行為有特定的不同的運作方式,覆蓋哪些方法 4通過尋找使用共同行為的子類找出更多抽象化的機會,我們必須觀察動物的子類找尋是否有可以組織歸納使用共同程式程式碼的部分 5完成類的繼承層次 當你呼叫物件引用的方法時,你會呼叫到與該物件型別最接近的方法,即最低階的會勝出。 即某個方法在子類中被覆蓋過,呼叫這個方法時會呼叫到覆蓋過的版本。 是一個 與 有一個 是繼承 不是繼承 單向繼承 4方法的覆蓋 5就點選 6遺產 子類可以繼承父類的成員。這包括了例項變數和方法。 父類可以通過存取許可權決定子類是否能夠繼承某些特定的成員。 public型別的成員會被繼承 private型別的成員不會被繼承 7繼承的好處 避免了重複的程式程式碼 定義出共同的協議

8多型

當你定義出一組類的父型時,你可以用子型的任何類來填補任何需要或期待父型的位置。 因為我會通過宣告為父型型別的物件引用來引用它的子型物件。 這樣編寫出真正具有適應性的程式程式碼的機會。

物件宣告、建立與賦值的三個步驟 重點在於引用型別與物件型別必須相符 宣告的是(引用):dog 建立的是:dog

多型中,引用型別與物件型別可以是不同的型別 宣告的是(引用):animal 建立的是:dog

運用多型時,引用型別可以是實際物件型別的父類。當你宣告一個引用變數時,任何對該引用變數型別可以通過IS A測試的物件都可以被賦值給該引用。 例: animal[] animals=new Animal[5]; animals[0]=new Dog(); animals[1]=new Dog(); for(int i=0;i

9覆蓋的規則

子類要覆蓋父類的方法時,你就得同意合約: 1引數必須要一樣,返回型別必須要相容 2不能降低方法的存取許可權 10過載(過載與多型無關) 同一個類中的兩個方法的名稱相同,引數不同 1返回型別可以不同 2不能只改變返回型別 3可以更改存取許可權

八深入多型

繼承只是個開始,要使用多型,我們還需要介面。我們需要超越簡單的繼承並前進到只有通過設計與編寫介面規格才能達成的適應性和擴充套件性。介面是一種純抽象的類。什麼是抽象類:就是無法初始化的類。

1不該初始化的class

我們可以寫出這樣的指令: Wolf awolf=new Wolf(); 也可以: Animal acat=new Cat(); 但是這樣會很奇怪: Animal ani=new Animal(); 哪有一種叫做Animal的動物呀。 這說明。有些類不應該被初始化。

2抽象類

我們一定要有Animal這個類來繼承和產生多型,但是要限制只有它的子類才能夠被初始化。 有一個辦法可以防止類被初始化,即讓這個類不能被new出來。 通過標記類為抽象類,那麼這個類就是不能建立任何型別的例項,編譯器不會讓你初始化抽象類。 你還是可以用這個抽象的型別宣告為引用型別給多型使用,這也就是當初為什麼要有抽象型別的目的。 抽象類除了被繼承過之外,是沒有用途、沒有值、沒有目的的。

3抽象方法

抽象的類代表此類必須要被extends過 抽象的方法代表此方法必須要被覆蓋過 你或許認為抽象類中的某些行為在沒有特定的執行時不會有任何的意義。 抽象的方法沒有實體。 如果你宣告出一個抽象的方法,就必須將類也標記為抽象類。你不能在非抽象類中擁有抽象方法。 為什麼要有抽象方法。抽象類的重點就在於可以被子類繼承的共同程式程式碼。 將可繼承的方法體放在父類中是個好主意,但有時就是沒有辦法做出給任何子類都有意義的共同程式程式碼,抽象方法的意義是就算無法實現出方法的內容,但還是可以定義出一組子型共同的協議。 這樣做的目的是多型!記住,你想達成的目標是要使用父型作為方法的引數、返回型別或陣列的型別。通過這個機制,你可以加入新的子型到程式中,卻又不必重寫或修改處理這些型別的程式。想像一下如果不是使用animal作為vet的方法引數程式,將必須為每一種動物寫出不同的方法,因此多型的好處就在於所有子型都會有那些抽象的方法。

你必須實現所有的抽象方法,實現抽象方法就如同覆蓋過方法一樣,你必須以相同的名稱。引數和返回型別創建出非抽象的方法。

4多型的應用

例: Public class MyDogList{ Private Dog[] dogs=new Dog[5]; Private int nextindex=0; Public void add(Dog d){ If(nextindex

5物件之母:object

終極物件 1equals(Object o)判斷兩個物件是否相等 2getClass()告訴你此物件是從哪裡被初始化的 3hashCode()列出此物件的雜湊程式碼,你可以把它想成是唯一的id 4toStirng()列出類的名稱和一個我們不關心的數字 覆蓋!! Object這個類不是抽象的類,為什麼允許創建出它的例項呢,是因為有時候你就是需要一個通用的物件,一個輕量化的物件,最常見的用途實線上程的同步化上面。 它有兩個主要的目的:一是作為多型讓方法可以應付多種型別的機制,以及提供java在執行期對任何物件都有需要的方法的實現程式程式碼。

6取出陣列元素

使用object型別的多型引用是會付出代價的 例:當你把物件裝進裡面時,會被當做Dog輸入輸出 ArrarList myDogList=new ArrayList(); Dog adog=new Dog(); myDogList.add(adog); Dog d= myDogList.get(0);輸出 例:當你把物件裝進裡面時,輸出會變成Object型別的引用 ArrarList myDogList=new ArrayList(); Dog adog=new Dog(); myDogList.add(adog); Dog d= myDogList.get(0);發生編譯錯誤,因為返回的是Object型別的

7編譯器對引用型別的檢查

例: Public void go(){ Dog adog=new Dog(); Dog samedog=getObject(adog); 錯誤,應改為Object sameDog= getObject(adog); } Public object getObject(Object o){ Return o; } 當一個物件被宣告為Object型別的物件所引用時,它無法再賦值給原來型別的變數。

再來看這個問題: Object o=alnimal.get(index); Int i=o.hashCode();正確! o.bark();錯誤!編譯器是根據引用型別來判斷有哪些method可以呼叫,而不是根據object確實的型別! O被宣告為Object型別的引用,只能通過o呼叫Object類中的方法。 8探索內部物件

9多型引用

當你把物件裝進ArrayList時,不管它原來是什麼,你只能把它當作是Object。 從ArrayList取出引用時,引用的型別只會是Object。 這代表你只會取得Object的遙控器。

10物件引用型別轉換

但是,一定有辦法可以讓ArrayList取出的物件恢復成Dog,如果你真的確定它是Dog,那麼你就可以從Object中拷貝出一個Dog引用,並且賦值 給Dog引用變數。 例: Object o=al.get(index); 這樣 引用object指向它 Dog d=(Dog)o; 這樣 引用Dog指向它 d.roam(); 例:如果還不能確定它是Dog,你可以使用 instanceof這個運算子來檢查。若是型別轉換錯了,你會在執行期遇到ClassCastException錯誤。 If(o instanceof Dog){ Dog d=(Dog)o; } 現在你知道JAVA是多麼的注重引用變數的型別。你只能在引用變數的類確實有該方法才能呼叫它。把類的公有方法當作是合約內容,合約是你對其他程式的承諾協議。

11多重繼承的麻煩

提出一個需求:親熱寵物和耍寶寵物 有哪些方法可以在程式中重用現有的類? 方法1採用最簡單的方法,把寵物方法加進Animal類中 優:所有動物都可以馬上繼承到寵物的行為。不需要改變子類的 程式。 缺:你什麼時候見到過和河馬親熱?貓和狗的親熱方法也不一樣。 方法2採用方法1,但是把寵物方法設定成抽象的,強迫每個動物子類都去覆蓋它們。 優:這樣就可以讓非寵物類的動物在覆蓋這些方法時,作出合理的動作,或者是什麼都不做。 缺:所有具體的動物都得實現寵物的行為,這樣很浪費時間。非寵物也得作出寵物外觀。並且給Animal類的定義變得有些侷限性,反而讓其他型別的程式更難以重複利用。 方法3把方法加到需要的地方。 優:只有寵物才會有寵物的行為。 缺:首先這樣失去了合約保證,其次多型無法起作用,你得對個別寵物設計程式。 方法4: 1一種可以讓寵物行為只應用在寵物身上的方法 2一種確保所有寵物的類都有相同的方法定義的方法 3一種是可以運用到多型的方法 那不就是,我們需要兩個上層的父類,創建出一個帶有寵物方法的抽象類Pet 讓Cat和Dog同時從Animal和Pet同時繼承,而非寵物就不需要繼承任何Pet的方法。

兩個父類:java不支援這種方式,因為多重繼承會有“致命方塊”的問題 因為這個形狀看起來像是撲克牌的方塊。 例: Digitalrecorder(burn()) Cdburner(burn()) dvdburner(burn()) Combodrive 允許致命方塊的程式語言會產生某種很槽糕的複雜性問題,因為你必須要有某種規則來處理可能出現的模糊性。額外的規則意味著你必須同時學習這些規則與觀察適用這些規則的特殊狀況。因此JAVA基於簡單化的原則而不允許這種致命方塊的出現。

12使用介面

介面可以解決多重繼承的問題而又不會產生致命方塊這種問題。 把全部的方法設為抽象的。 如此一來,子類就得要實現此方法。 介面的定義:public interface Pet{} 介面的實現:public class Dog extends Canine Implements Pet{}

介面的作用:多型!若你以介面取代具體的子類或抽象的父類作為引數或返回型別,則你就可以傳入任何有實現該介面的東西。這麼說吧,使用介面你就可以繼承超過一個以上的來源。類可以繼承某個父類,實現其他的介面。同時其他的類也可以實現同一個介面。因此你就可以為不同的需求結合出不同的繼承層次。

不同繼承樹的類也可以實現相同的介面! 例: Robot pet animal Robodog dog 當你把一個類當做多型型別運用時,相同的型別必定來自同一顆繼承樹,而且必須是該多型型別的子類。 例:canine 的引數可以接受wolf和dog,但無法接受cat或hiippo. 但是你用介面來作為多型型別時,物件就可以來自不同的繼承樹了。唯一的條件就是該物件必須是來自有實現此介面的類。 允許不同繼承樹的類實現共同的介面來說很重要。 如果你想要將物件的狀態儲存在檔案中,只要去實現 serializable這個介面就行。打算讓物件的方法以單獨的執行緒來執行嗎?沒問題,實現runnable吧。

還有,類可以實現多個介面! 例: Public class Dog extens Animal implements Pet,Saveable,paintable{}

要如何判斷應該是設計類、子類、抽象類、介面呢? 1如果新的類無法對其他的類通過isa測試,就設計不繼承其他類的類 2只有在需要某類的特殊化版本時,以覆蓋或增加新的方法來繼承現有的類 3當你需要定義一群子類的模板,又不像讓程式設計師初始化此模板時,設計出抽象的類給他們用 4如果想要定義出來的類可以扮演的角色,使用介面

呼叫父類的方法 如果創建出一個具體的子類並且必須要覆蓋某個方法,但又需要執行父類的方法時要怎麼辦?也就是說不打算完全地覆蓋掉原來的方法,只是要加入額外的動作要怎麼辦? Super可以在子類中呼叫父類的方法 例: Abstact class report{ Void runreport(){ } Void printreport(){ } }

Class buzzwordsreport extends report{ Void runreport(){ Super.runreport(); Buzzwordcompliance(); Printreport(); } Void buzzwordcompliance(){ } }

九物件的前世今生

這一章會討論物件如何建立、存在於何處以及如何讓儲存和拋棄更有效率。這代表我們會述及堆、棧、範圍、構造器、超級構造器、空引用等等。

1物件與變數的生存空間

棧與堆:生存空間 方法呼叫及區域性變數的生存孔家棧stack 物件的生存空間堆heap 所有的物件都存活與可垃圾回收的堆上

例項變數:宣告在類中而不是方法中。存在於所屬的物件中。 區域性變數:和方法的引數都是宣告在方法中。它們是暫時的,且生命週期只限於方法被放在棧上的這段時間,也就是方法呼叫至執行完畢為止。

2stack上的方法

方法會在棧裡面堆在一起。棧頂上的方法是目前正在執行中的。

3區域性變數的空間

有關物件區域性變數 區域性變數時存在於棧上的,物件存在於堆上的。 若這個區域性變數是個物件引用,只有變數本身會放在棧上,物件本身只會存在於堆上。 例: Public class stackref{ Public void foof(){ Barf(); } Public void barf(){ Duck d=new Duck(24); } } 棧:barf() foof() d 堆:Duck物件 不論物件是在哪裡宣告的,它總會執行在堆上。

為什麼要知道棧和堆的機制?如果你想要了解變數的有效範圍、物件的建立、記憶體管理、執行緒和異常處理,則認識棧和堆是有必要的。

4例項變數的空間

例項變數存在於物件所屬的堆空間上。 若例項變數是個物件, 例1:物件帶有引用到antenna物件的變數,但是實際上沒有初始antenna物件的情形 Public class cellphone{ Private antenna ant; } 堆:cellphone (antenna) 例2:物件帶有一個新建出的antenna物件 Public class cellphone{ Private antenna ant=new antenna(); } 堆:cellphone 、antenna 5創造物件的奇蹟 物件的宣告、建立、賦值 例: Duck d=new Duck(); 看起來很像是呼叫Duck()這個方法,但其實我們在呼叫Duck的建構函式。

6建構函式

建構函式看起來很像是方法,感覺上也很像方法,但它並不是方法。它帶有new的時候 會執行的程式程式碼。換句話說,這段程式程式碼會在你初始一個物件時執行。 唯一能夠呼叫建構函式的辦法就是新建一個類。

你可以幫類編寫建構函式,但如果你沒有寫,編譯器會偷偷幫你寫。 構造方法沒有返回值,名稱與類的名稱相同。

7鴨子的初試狀態

例1:新建Duck的初始化 Public class Duck{ Int size; Public Duck{ System.out,prinbln(“q”); } Public void setsize(int newsize){ Size=newsize; } }

Public class useduck{ Public static void main(){ Duck d=new duck(); d.setsize(42); } } 例2:使用建構函式來初始化Duck的狀態 Public class Duck{ Int size; Public Duck(int ducksize){ System.out,prinbln(“q”); Size=newsize; System.out,prinbln(“size is”+size); } }

Public class useduck{ Public static void main(){ Duck d=new duck(42); } } 例3:為難! Public class Duck{ Int size; Public Duck(int ducksize){ If(newsize==0){ Size=27; }else{ Size=newsize; } } 例4:需要有兩種方法來創建出新的duck Public class Duck{ Int size; Public Duck(){ Size=27; } Public Duck(int ducksize){ Size=newsize; } } 這兩種構造方法是過載的。

8建構函式的覆蓋

編譯器只會在你完全沒有設定建構函式時才會呼叫,預設的建構函式是沒有引數的。 如果你已經寫了一個有引數的建構函式,並且你需要一個沒有引數的建構函式,你必須自己寫。

如果類有一個以上的建構函式,則引數一定要不一樣。 過載建構函式的意思代表你有一個以上的建構函式且引數都不相同。

9父類的建構函式

Object animal hippo Hippo is a animal,animal is a object 如果你要創建出hippo,也得創建出animal與object 建構函式鏈

在建立新物件時,所有繼承下來的建構函式都會執行。 這代表每個父類都有一個建構函式,且每個建構函式都會在子類物件建立期間執行。 就算抽象的類也有建構函式,雖然你不能對抽象的類執行new操作,但抽象的類還是父類,因此它的建構函式會在具體的子類創建出例項時執行。 在建構函式中,用super呼叫父類的建構函式的部分。 例: Public class animal{ Public animal(){ System.out.println(“making a animal”); } }

Public class hippo extends animal{ Public hippo (){ System.out.println(“making a hippo”); } }

Public class testhippo{ Public static void main(string[] args){ System.out.println(“staring”); Hippo h=new hippo(); } } 結果: Staring Making a animal Making a hippo

如何呼叫父類的建構函式? Public class duck extends animal{ Int size; Public duck (int newsize){ Super(); Size=newsize; } } 要用super()呼叫! 如果我們沒有呼叫super(),那麼編譯器會幫我們加上super()的呼叫。預設加上的是加上沒有引數的這種哦。 所以編譯器會有兩種涉入建構函式的方式,1如果你沒有編寫建構函式2如果你有建構函式但沒有呼叫super()。

對super()的呼叫一定是建構函式的第一條語句,因為父類的部分必須在子類建立完成之前就必須完整的成型。因為子類物件可能需要動用到從父類繼承下來的東西,所以那些東西必須要先完成。

有引數的父類的建構函式 如果父類的建構函式有引數該怎麼辦?你能傳值進去麼? 如果不傳值,那麼沒有無引數的建構函式的類將不能被繼承。 如果可以傳值的話: Animal getname() 返回name例項變數的值 此例項變數是被標記為私有的,但hippo這個子類把getname()繼承下來, Public abstract class animal{ Private string name; Public string getname(){ Return name; } Public animal(string thename){ Name=thename; } } Hippo有getname()這個方法但是沒有name的例項變數。 Hippo要靠animal的部分來維持name例項變數,然後從getname()來返回這個值,但anmial如何取得這個值呢? Public class hippo extends animal{ Public hippo (string name){ Super(name); } } 唯一的機會是通過super()來引用父類,所以要從這這裡把name的值傳進去,讓animal把它存到私有的name例項變數中去。 Public class makehippo{ Public static void main(string[] args){ Hippo h=new hippo(“buffy”); System.out.println(h.getname()); } }

10使用this()

從某個建構函式呼叫過載版的另一個建構函式。 如果有某個過載版的建構函式除了不能處理不同型別的引數之外,可以處理所有的工作,那要怎麼辦? 你不想讓相同的程式程式碼出現在每個建構函式中,所以你想把程式程式碼只擺在某個建構函式中。 如此一來 ,所有的建構函式都會先呼叫該建構函式,讓它來執行真正的建構函式。 通過this();this就是個對物件本身的引用。 每個建構函式可以選擇呼叫super()或this(),但是不能同時呼叫。

使用this()來從某個建構函式呼叫同一個類的另外一個建構函式。 This()只能用在建構函式中,且必須是第一行語句。 Super和this不能兼得。

Public mini extends car{ Color color; Public mini(){ This(color.red); 無引數的建構函式以預設的顏色呼叫真正的建構函式 } Public mini(color c){ Super(“mini”); 這才是真正的建構函式 Color=c; } Public mini(int size){ This(color.red); 並不能同時呼叫 Super(size); } }

11物件的生命週期

區域性變數:只會存活在宣告該變數的方法中 例項變數:壽命與物件相同,如果物件還活著,則例項變數也會是活的。 12資源回收 有3種方法可以釋放物件的引用: 1引用永久性離開它的範圍 2引用被賦值到其他的物件上 3直接將應用設定為null

十數字很重要

1math類 像round()abs()max()等數學運算方法其實不需要例項變數值,在寶貴的堆上建立很浪費 因為這些方法都是靜態的,所以你無需math的例項,你會用到的只有它類的本身。 Int x=math.roubnd(42.2); 這些方法無需例項變數,因此也不需要特定物件來判別行為。 2靜態方法 Java是面向物件的,但若處於某種特殊的情況下通常是實用方法,則不需要類的例項。 Static這個關鍵字可以標記出不需類例項的方法。一個靜態方法代表說:一種不依靠例項變數也就不需要物件的行為。 非靜態方法:以引用變數的名稱呼叫非靜態方法 靜態方法:以類的名稱呼叫靜態方法

帶有靜態方法的含義: 通常你會寫出main()來啟動或測試其他的類。從main()中建立類的例項並呼叫新例項上的方法。 取得新物件的方法只有通過new或序列化。

靜態的方法不能呼叫非靜態的變數 靜態的方法是在無關特定的類的例項情況下 執行的。因為靜態的方法是通過類的名稱;來呼叫,所以靜態的方法無法引用到該類的任何例項變數。在此情況下,靜態的方法也不會知道可以使用哪個例項變數值。 如果你嘗試在靜態的方法內使用例項變數,編譯器會不知道是哪個例項的變數,靜態的方法是不知道堆上有哪些例項的。

靜態方法也不能呼叫非靜態的方法 非靜態的方法做什麼?以例項變數的狀態來影響該方法的行為。

如果類只有靜態的方法,你可以將建構函式標記為private以避免被初始化。 3靜態變數 靜態變數的值對所有的例項來說都相同。 優點:被同類的所有例項共享的變數 例1:每個duck在初始化時候duckcount的值都是0 Class duck{ Int duckcount=0; Public duck(){ Duckcount++; } { 例2: Public class duck{ Private int size; Private static int duckcount=0; 靜態變數只會在類第一次載入時被初始化 Public ducki(){ Duckcount++; } Public void setsize(int s){ Size=s; } Public int getsize(){ Return size; } } 靜態變數是共享的,同一個類所有例項共享一份靜態變數,每個類一個 例項變數:每個例項一個

靜態變數的起始動作 靜態變數會在該類的任何物件建立之前就完成初始化 靜態變數會在該類的任何靜態方法執行之前就初始化。

靜態變數也是通過類的名稱來存取。

4常數 靜態的final變數是常數 一個被標記為final的變數代表它一旦被初始化之後就不會改變,也就是說類載入後靜態final變數就一直會維持原值。 常數變數的名稱應該要都是大寫字母。

Final不只用在靜態變數上 也可以用final來修飾非靜態的變數,包括了例項變數、區域性變數或是方法的引數。 不管哪一種,這都代表了它的值不能變動。 可以用final防止方法的覆蓋或建立子類。

1Final的變數代表了你不能改變它的值 2Final的方法代表了你不能覆蓋掉該方法 3Final的類代表了你不能繼承該類(也就是建立它的子類)

如果類已經是final了,再標記final的方法是不是很多餘? 對,如果一個類不能被子類化,則它的方法根本就無法覆蓋。 5math方法 Abs()random()round()min()max()

6包裝類 當你需要以物件方式來處理prinitive主資料型別時,就把它包裝起來。 Boolean、character、byte、short、integer、long、float、double 例: Int i=78; Integer iwap=new integer(i);

Int unwrapped=iwap.intvalue(); 例: Int x=32; Arraylist list=new arraylist(); List.add(x); java5.0以上才能這麼用

5.0前主資料型別就是原始型別,而物件引用就是物件引用,兩者絕無交換使用的方法。 要互動使用就得靠程式設計師進行包裝或拆開包裝的動作。 Integer 與int兩者毫無關係可言,只是integer帶有一個int型別的例項變數。 例:無autoboxing Public void donumsoldway{ Arraylist listofnumbers=new arraylist(); Listodnumbers.add(new integer(3)); Integer one=(integer)listofnumbers.get(0); Int intone=one.int