第一章 進入Java的世界(基本概念)
主要介紹了Java的工作原理,發展簡史,程序結構和一些簡單的語法。學過其他語言的人表示這章完全沒有壓力。
1, 程序的層次:源文件(source file)->類(class)->方法(methods)。
2, Java里面integer和boolean不相容。
3, 語法與C差不多,不過作者好像一直很反感拿C與Java作比較。
第二章 拜訪對象村(類與對象)
一開始用了一個巨冷的故事來闡述面向過程編程與面向對象編程的差別(結果當然是面向對象優勝= =先保留意見吧)。
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, 可以從方法里面返回值,聲明了返回最好要返回(我敲代碼時發覺時聲明了返回不返回會報錯的,但P78最后一個問題的回答并不是這樣的??囧),一般情況下只能返回一個值,但是可以返回一個數組,再深一層的,可以返回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, 程序設計的第一步是高層設計,把程序的基本架構抽象出來。(想起了萬惡的NS圖)
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文檔(真希望能具體點)。
第七章 對象村的優質生活(繼承與多態)
我認為繼承和覆蓋是前十二章里面Java里面最強大的機制,拓展性,獨立性,適應性,易改性???多態什么的就是為了配合這個強大的機制而存在的。
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出來。抽象類的作用就是在防止被初始化之余能被繼承以維持多態。(*書上提到特例:抽象類可以有static成員,目前不明白)。抽象類必須要被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送出信息到聊天服務器上->服務器將信息送給所有的來賓(一開始對最后一步有疑問,參看P488就恍然大悟了)
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)(目前在學C++版的數據結構…討厭的課程)
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(ArrayListanimals),注意這里的extends依然和implements一起都是is的意思。
第十七章 發布程序(包,jar存檔文件和部署)
文件部署,打包成jar什么的,我希望有懶人工具能幫忙打包。
1, 部署分成:完全在本機的Executable Jar,完全在遠程的Servlets和介乎兩者之間的JWS(我愛翻譯成“巨猥瑣”)。
2, 源代碼和類文件的分離:源代碼放在source,類文件放在classes,使用命令-d(書上說-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)。因為很強大,所以書上也沒有篇幅去細說。后面是實現方法和一堆堆代碼,看得我產生了嚴重的抵觸情緒。