think in java 筆記


今天在整理資料的時候,突然發現以前看think in java(java編程思想)時做的筆記,感覺還不錯就拿來分享下,也是秉承我一貫的發表是最好的記憶

建議大家都去看下這本書,無論是基礎的內容還是。。都是講的挺仔細的

 

 

早期的一次java演講,Bill Joy(創始人之一)聲稱“java = C + + - -”

 

原則:程序設計就是將發生變化的東西同保持不變的東西分隔開

//以上是名言

 

1.實現方案的隱藏:

 

(1)將屬性都設為private,避免直接訪問屬性,而只是提供相應的方法來對屬性的訪問。(2)抽象化,將實現類與接口相分離,對外界只提供相應接口,而隱藏方法的具體實現,作用:a.防止不該接觸實現細節的程序員去改變實現的細節,而影響其他用戶的使用。b.允許庫的設計人員修改內部的實現細節,而不會對客戶程序員造成什么影響。因為注入他們程序的只是接口。

 

 

 

2.方案的重復使用:

 

代碼與設計方案的重復使用是面向對象中最重要的部分。

 

包含(組織)關系:例如單獨將一個變速器設為一個類,而將汽車設為一個新類,將變速器類的對象注入到汽車這個新類中,這樣的化需要使用到變速器的車類都可以使用到,這就是很好的實現了代碼的重復使用,如果將這個類並在每一個汽車類中,那么有幾種汽車就要重復代碼幾遍,這樣的設計就會顯得很差。

 

繼承關系:一種重要的內部處理是,將衍生類當基礎類來處理,即有一個參數為基礎類的方法,此時我們可以調用方法而傳遞的參數是一個衍生類,程序會正確的處理成一個衍生類型,這個叫做UpCasting(上溯類型)。

 

程序會根據傳遞的參數的類型,會自動處理的去調用相應類的方法(可能子類重寫了父類的方法,),編譯器和運行系統會負責所有的實現細節,不用我們自己控制的,這種情況叫多形性,實現多形性的方法叫動態綁定。

 

我們在選擇類的關系時,首先應該考慮組織(包含)關系,其次再考慮繼承關系,繼承會讓程序變的很復雜

 

 

 

3.集合的使用:

 

最好的方式是集合的選擇能根據自己的使用方式自動改變積累的實現方式,使得我們不用根據不同的需求(select,delete,update),來進行集合的更換(典型的像vector與list),但另一個方面,集合方面的效率的開銷相對與垃圾處理器的開銷和在window下運行的開銷,算不上什么了。

 

在進行集合元素的迭代的時候最好選擇繼承器(iterator),使用與所有的集合類。

 

 

 

4.java是實現單根結構的設計模式的,即所有的類最終都是從一個基礎類中進行繼承的(Object類)。這樣使得所有類的所有對象都有一個通用的接口,使得最終都屬於同樣的類型。所帶來的方便:a.這能使得所有的對象都擁有一些基本的操作,並且所有的對象都是在內存堆中創建的,可以極大的簡化參數的傳遞。

 

b.更方便的實現垃圾收集器,可以將一些必要的支持安裝於基礎類中(即Object),收集器可以將適當的消息發送給所有的對象。

 

 

 

5.java編程比C++簡單:

 

a.  java使用單根結構,並且我們只能在內存堆中以一種方式來創建對象(new)而不能在堆棧中進行創建,而C++允許在堆棧中進行創建,並且是分配,釋放存儲空間最有效的方式,而在內存堆中進行對象的創建是要在運行期間付出昂貴代價的。 b. java使用垃圾處理器來進行垃圾的回收,然后自動釋放那些對象所占據的內存,而C++中,在用完一個對象后必須顯示將其刪除。(java系統的垃圾收集器一直是一個不清楚的結構,有時我們要在特殊的程序中避免垃圾收集器(實時系統))。

 

 

 

6.多線程:

 

多線程的處理在一般情況下還是蠻簡單的,但當多個線程同時運行,並試圖訪問同一個資源,這樣的話就必須進行一些處理:對共享的資源在使用時必須進入鎖定狀態,就是每個線程按順序進行訪問該資源,訪問時資源被鎖定,訪問后資源被解鎖,

 

同一時間只有一個線程能使用特定的內存空間(屬於資源的一種),為實現該目的必須使用synchronized關鍵字,其他類型的資源必須由程序員明確鎖定,通常要求程序員創建一個對象,用它來代表一把鎖,每次多個線程訪問該資源時都必須檢查該鎖。在設計單例模式也用到:http://www.cnblogs.com/shenliang123/archive/2012/03/26/2417968.html

 

 

 

7.web: 客戶機/服務器:

 

(服務器:將各種元素集中到一起,信息倉庫,用於投遞信息的軟件以及信息和存放該軟件的機器。)

 

 

 

8.java不是十分容易就可以學會的語言,java中的類就是一種類型,只不過是一種復雜的類型。

 

 

 

9.在html中可以嵌入java小程序片(applet),在訪問一個服務器時,服務器會根據請求將html和applet一並發送到客戶的瀏覽器上,這個應用還是蠻好的。

 

 

 

10.服務器端編程:瀏覽器向服務器發出復雜的請求通常涉及數據庫的事務,服務器進行處理后會將它格式化為html作為結果返回,這些請求都是需要服務器端的代碼進行處理的,所有服務器端的編碼還是很重要的(servlet)。

 

 

 

11.java與C++比較:各有各的優勢,作用於不同的領域,java強大的類型檢查和錯誤控制系統是不能比擬的,java的運行速度是不能跟C++比擬的,即使已經得到了大大的改變。

 

 

 

12.連接數據庫可以選擇jdbc,hibernate,jdo,jdo和hibernate相似都是面向

 

對象的,但jdo是面向數據庫表的,而hibernate是面向類的對象的

 

 

 

 

 

第二章,一切都是對象

 

1.用句柄來操作對象:

 

在java的程序中一切都可看作是對象,但操作標示符實際上是一個指向對象的“句柄”,就像電視機和遙控器一樣,(電視機就是一個對象,遙控器就是一個句柄,其實所有的操作都是在遙控器上進行的),但其實不是每個句柄都要對應某個對象,但最好這樣,就是每次申明一個變量時都初始化。

 

 

 

2.java中數據的保存位置6個:

 

a.寄存器(處理器內部):存儲量很小,是由編譯器分配的,我們並沒有直接的控制權。

 

b.堆棧(位於隨機存儲訪問區[RAM]):一般對象的句柄都是存儲在這里的,通過指針的移動來保存,釋放內存,但對象是不存儲在這里的,在存儲時編譯器必須准確知道保存的所有數據的長度和存儲時間,影響靈活性。

 

c.堆(內存堆RAM):用來保存對象,只要是有new的代碼來創建對象,就能在運行期間自動進行保存,使得編譯器不用知道要存儲多少對象和對象保存的時間,更有靈活性,但因此而付出的是運行時的內存分配(例外的,java為了對那些特別小並且簡單的對象訪問的高效,不使用new來創建,創建一個並非句柄的變量來存儲實際值,存儲在堆中)。

 

d.靜態存儲:位於RAM的指定位置,用static關鍵字指出一個對象的某些元素是靜態的,但一個對象永遠不會處於靜態存儲區。

 

e.常數存儲:將常數直接存儲在程序代碼內部,

 

f.非RAM存儲區

 

 

 

3.java中增加了兩個類,用於進行搞進度的計算:BigInteger和BigDecial.

 

作用域(scope):由花括號的位置決定。Java中在一個大的作用域中已經申明變量X了,那么不能更小的作用域中進行重新的申明。

 

 

 

4.java對全局變量會賦初值(boolean默認值是false),但若為局部變量就不會進行初始化,在編譯時報錯,因此局部變量必須要進行初始化。

 

 

 

5.java中調用一個類中的方法,先實例化一個對象(static除外),然后用對象來調用正確的方法,面向對象的程序設計通常稱為“向對象發送信息”,如

 

Int x = a.f(); 其他a為對象,f()為消息。

 

 

 

6.靜態方法static:使用靜態方法主要是為了能直接通過類來調用它的方法,在靜態方法中只能使用靜態的成員變量,因為非靜態的成員變量必須通過對象來實例化,反正只要抓住靜態方法不要創建類,就可以解決其他的一些問題了。

 

 

 

7.文檔注釋:

 

類文檔標記:

 

@see:類名/完整類名/完整類名#方法名,表示引用其他文檔中的類

 

@version:版本信息,   @author:作者信息,  Html的嵌入

 

變量文檔標記:

 

只能包括嵌入的html和@see引用

 

方法文檔標記:除了包括嵌入的html和@see引用外還包括

 

@param 參數名 說明  @return 返回值說明  @exception 完整類名 說明

 

 

 

8.從一個對象到另一個對象的賦值,實際就是將句柄從一個地方復制到另一個地方,那么C = D意味着C,D句柄都是指向D開始所對應的對象。

 

還有種現象叫“別名”:就是將一個對象A復制給另外一個對象B,那么B將會被垃圾收集器自動清除,此時B相當於是A對象的別名,指向的都是A對象,這時用A,B都可以改變對象中的屬性值。關於別名下面會進行詳細的說明

 

 

 

9.邏輯運算符:&&和||屬於運算具有“短路“的特點,就是在明確表達式的返回的值后就不在向下進行計算了,而&和|就不具有這樣的特點,會將所有的表達式都進行計算后進行返回

 

 

 

10.java里需要用到逗號的唯一場所的就是for循環。

 

 

 

11.C++含有sizeof()方法,來得到數據類型在不同的位數電腦上所占的位數,而java是不含有此方法的,因為java的所有數據類型在所有的機器上大小都是相同的。

 

 

 

12.標簽:對java來說唯一使用到標簽的地方就是在嵌套循環語句前,位置就是在緊靠在循環語句的前面,兩者之間最好不要插入其他的任何東西,在循環語句前嵌入標簽的理由是,可以讓break或continue跳出多重循環,因為理論上break和continue都只是中斷當前的循環。

 

 

 

13.將float或double類型的數據轉化為整數值后,總是將小數部分“砍掉”,而不做任何的進位處理,Math.rondom()產生的隨機數的范圍是[0,1).

 

14.方法過載(重載):

 

就是相同的方法名,但方法參數的類型,數量,順序不同,而單單是方法的返回值不一樣就不能叫做方法過載,因為有時候我們並不關心方法的返回值,如調用f();編譯器根本不能判定被調用的方法是含有返回值的還是不含有返回值的。

 

 

 

15.有個疑問,如果有兩個同類型的對象,那么如果為這兩個對象調用同一個方法呢?如:

 

class Ban{

 

    f(){

 

    ………};

 

}

 

Ban ban1 = new Ban();   Ban ban2 = new Ban();  ban1.f(1);  ban2.f(2);

 

那么只有一個f()方法,那么怎么知道是ban1調用的還是ban2調用的呢?

 

其實編譯器會為我們做一些幕后的操作,他會將句柄當做自變量傳遞給方法f();  所以前面的兩個方法在編譯后變成了f(ban1, 1);  f(ban2, 2);

 

 

 

16.this關鍵字:

 

this都是指向這個對象或當前對象,而且本身會產生當前對象的一個句柄。

 

  1. 在構建器里調用構建器:可能需要在一個構造器中調用例外一個構造器,為了防止代碼的重復,就用this,但只能調用一次,不能調用兩次,而且必須放在最前面。

 

 

 

17.在一個類的內部定義一個對象句柄,如果不將其初始化為一個新對象,那么那個句柄就會獲得一個空值。

 

 

第5章:隱藏實施過程

 

 “進行面向對象的設計時,一項基本的考慮是:如何將發生變化的東西跟保持不變的東西相分離”

 

  1. java 解釋器的工作程序(瀏覽器中一般都含有java解釋器):首先:它會找到環境變量classpath變量(在安裝jdk時必須進行配置),classpath會包含一個或多個目錄,它們作為根,從這里展開對.class文件的搜索。
  2. 解釋器在遇到import時,它會搜索classpath下指定的路徑,在查找子目錄(提供的包名),然后查找名稱適當的已編譯的文件。
  3. 有時我們想自己創建一些新的工具類,那么可以將這些類編譯放到tools目錄下,如將System.out.println()創建一個別名,那么就可以自己寫一個類:

 

   

 

 

 

 

 

 

 

 

 

  1. java的默認的訪問沒有關鍵字,但它通常成為“友好(friendly)”訪問,這意味着現在包內的其他的所有類都能訪問該友好類成員,但對包外的類是私有的,因此也說“友好”元素具有“包訪問”權限。但如果那個類中有一個申明public 的static方法,那么包外還是能夠通過類名來進行該靜態方法的訪問,雖然不能創建該類的對象。
  2. 子類實例化過程,子類對象在實例化之前程序會默認首先調用父類中的構造方法之后再調用子類自己的構造方法,但調用的基類的構造方法是默認的構造方法,如果要調用含有參數的父類構造方法,必須顯示的調用(用super關鍵字)。其實在子類構造中隱含了一個super()語句,因此如果一個類的構造方法被私有化后,那么這個類就不能被繼承了。被子類覆寫的方法不能擁有比父類方法更嚴格的訪問權限。可以通過super來調用父類中的方法。父類總的private方法是不能被覆寫的。
  3. 我們在創建一個類的時候可以這樣設計:將public成員寫在最開始,接着是protected, private成員,這樣做的好處是能自上而下進行閱讀,首先看到對自己最有用的(public).
  4. 每種非基本數據類型都含有一個toString()方法。有時我們為了輸出方便我們需要重寫該方法。
  5. 創建一個對象句柄:在下面情形下可以對其初始化一個對象。a.對象定義的時候,這意味着他們在構造器創建之前肯定得到了初始化。b.在那個類的構造器中。C.緊靠在實際要求使用那個類的時候。
  6. 合成就是在一個類中加入另外一個類的句柄,然后初始化一個對應的對象。在合成與繼承之間如何選擇: a.當想利用新類內部一個現有類的特征,而不想使用它的接口,就使用合成,就是說可以嵌入一個現有類的對象類實現新類的特征,使得新類的用戶看到的是我們已定義的接口,而不是嵌入類的接口,這種需求就要在新類中嵌入現有類的private的對象。Car就是一個很好的例子,有engine, door, window, wheel等的合成。繼承與合成是設計類時非常重要的,要考慮詳細,可以到項目完成時在重新構想一邊,看看結構是不是合理。選擇的重點就是是否需要使用現有類的接口,需要就用繼承,如果只是為了實現新類的接口而需要某一個現有類特征,就使用合成。

 

總結繼承的關系 = “新類屬於現有類的一種類型”

 

10.上溯造型(對多形性):表示將子類的句柄轉化為父類的句柄,可以去調用參數為父類的方法,但傳遞的參數卻是子類的句柄。這樣做很方便,能省掉很多的代碼,否則在一個類中寫一個對基類和衍生類都能調用的方法,那么有多少衍生類就需要重復寫這個方法幾遍,如果采用上溯造型就可以只寫一個參數為基類的即可,子類也能作為參數調用,而且若以后我們增加了更多的衍生類,那么也不用於更改該方法,是軟件具有更好的“擴展性”。而由於方法在編譯期間是不能判斷傳入的參數是該基類的哪一個衍生類,因此為了能順利完成調用,還需要“后期綁定”,更准確的講叫“動態(運行期)綁定”, 在運行期判斷相應的對象的類型,並准確執行相應的方法(這樣必須在對象中安插某種特殊的標記)。但如果一個方法申明為final,那么編譯器就不會執行“動態綁定”,因此執行速度就增加了。這樣我們就能使用一種新的實例化方式:基類 句柄 = new 衍生類();  在里實際上創建的是一個衍生類對象,但句柄指向的卻是基類,將該參數傳入相應的方法並調用該句柄所對應對象的方法,此時編譯器會知道會去調用衍生類的覆蓋方法(動態綁定已經生效)。還有一點,如果衍生類中有個方法的方法名跟基類的相同,但參數的類型or順序or個數不一樣,那么這個同樣叫做過載(重寫)。

 

11.final的使用:a.基本數據類型中使用final修飾表示該數據是一個常數,永遠不能改變,並且必須要賦初值(可以是一個表達式),而如過是修飾一個句柄(即對象或數組),那么只是不能再將該句柄指向其他的新對象,但可以改變對象的屬性或數值。當用static和final同時修飾時該數據就是一個全局常數(一般采用大寫)。無論是將其定義為static還是定義為final,在編譯期間都是不知道值的,只有在運行期(初始化)才知道。b.自變量用final修飾,如方法的參數被定為final,那么在方法內部不能改變該參數句柄所對應的對象,只能讀取它。c.方法被final修飾,理由一:不想讓繼承類來覆蓋和改寫該方法,防止繼承類改變它本來的含義。理由二:會使代碼的執行效率變高。(但這樣做要慎重)。

 

12.類的整個初始化順序(包括繼承):裝載程序先到外面去找到那個類,找到后查看是否有基類(extends),有的話隨之將其載入,無論是否需要生成基類的對象,這個過程都會發生,如果該基類還含有基類,也將其載入,依此類推。之后會在根基類中執行static初始化,在到衍生類中初始化,以此類推。保證這個順序是很重要的,因為可能衍生類的初始化可能依賴基類成員。至此必要的類都已經裝載完畢,可以進行對象的創建,首先,這個類中的基礎類型數據都是初始化為默認值,對象句柄初始為null(為對象分配的存儲空間初始化成二進制0),隨后調用基礎類構造器,這個調用是自動的,我們也可自己顯示調用(super),如果基類的構造方法中含有基類的抽象方法,那么會調用子類的方法實現,基礎類的構建采用與衍生類構建器完全相同的處理過程。基礎類構建器完成后,實例變量會按本來的順序進行初始化。最后執行構建器的剩余部分。

 

13.抽象類:里面的方法可以只有聲明,沒有方法主體,也可以有完整的方法,此時類必須聲明為abstract,而在衍生類中必須實現基類的抽象方法,也有例外,如果不實現那么該衍生類也要成為抽象類。抽象類是不能被實例化的,保證了它的“純潔性”。接口(interface):是對抽象類更深一步的抽象,接口也包含了基本數據類型的數據成員,但他們默認為static和final.在一般情況下,我們首先會選擇接口,因為它同時獲得了抽象類和接口的好處。我們還能extends繼承一個接口來擴展新接口的內容,而且此時支持多重繼承。

 

14.由於置入一個接口的所有字段都自動具有static和final屬性,所有說接口時對常數值進行分組的一個好工具,在外部通過 接口.常數 進行引用,但獲得的只是一個基本數據類型的數,不擁有額外的類型安全性,例如:本想用來代表一個月份的int變量,可能獲得的是一個整數值。下面處理比較合理:

 

 

 

 

 

 

 

這是一個final類,其他類不能繼承它,並且構造方法是私有的,就不能實例化了,唯一的實例就是那些final static對象,它們是在類本身內部創建的,這樣就可以通過名字或數組的索引來調用,在main中我們可以知道此時是類型安全的,因為m是一個對象,只能將其分配給Month2。

 

15.內部類:將一個類定義置於另一個類中,對內部類的需求並不會太明顯,至少不會立即感覺到自己要使用內部類了,有種情況就是外部類有一個方法而這個方法的返回值就是內部類的句柄,想在外部類非static方法內部之外生成內部類的一個對象,必須將那個對象的類型設為“外部類.內部類”。使用內部類的情形:(1)我們准備實現某形式的接口,使自己能創建或返回一個句柄,例如:當我們准備上溯到一個基礎類(特別是接口),內部類就開始發揮其關鍵作用了(從用於實現的對象來生成一個接口的句柄具有上溯造型到基礎類相同的效果),代碼在181,(2)要解決一個復雜的問題,並希望創建一個類,用來輔助自己的程序,並且不願意將其公開,在方法的內部創建一個內部類,或者在任意的一個范圍內創建一個內部類,但使用該內部類只能在內部類的內部,外部就不能調用了。還有匿名內部類,不是很清楚如何正確的使用它們。內部類有一個重要的特點就是可以范圍該類中的被封裝的私有成員變量。而且很重要的一點:就是內部類的對象默認持有創建它的那個封裝類的一個對象句柄。

 

16.構建構造器時的一個特別有效的規則:盡可能簡單的方法使對象進入就緒狀態,如果可能盡量避免調用任何的方法,在構建器內唯一能夠安全調用的是基類中具有final的屬性方法(private也可,自動為final),這些方法不能被覆蓋,不會受到子類的影響(基類的構造方法中調用該類中的抽象方法來對對象進行初始化,但該抽象方法已經被子類覆蓋,那個在調用父類的構造方法的時候,根據動態綁定原則,會自動去調用被子類覆蓋的方法,但由於參數的原因,使得該對象可能未被正確的初始化)。

 

17.在“上溯造型”中能夠通過基類來調用子類的所有方法,那么必須保證子類只含有基類的所有方法,不含有額外的方法。此時我們為了能調用子類額外的方法,那么必須使用“下溯造型”,但“上溯造型”肯定是安全的,因為基礎類不可能擁有一個比衍生類更大的接口,故能保證基礎類發送的每一條消息衍生類都能接受到,但“下溯造型”就不行了。

 

 

 

 

 

 

 

第八章:對象的容納

 

1.數組:length只表示該數組能容納多少元素或句柄,並不能得知實際包含多少,數組的訪問速度比集合類要快,但其他的操作就不行,不夠靈活,數組的大小必須事先確定,並且一旦創建並且初始化就不能刪除里面的元素,以為占有的內存是不能釋放的。

 

2.集合類:集合類在不使用范型的情況下,是不能自主控制放入集合內的對象的類型的,因為集合類定義的是一個根類型Object,但如果放入集合的對象不是同一個類型,那么在取出集合類對象時就會報錯了,除了范型,控制集合中存入的對象的類型的就是將該集合放入一個方法中,該方法的參數就是某一對象的類型,然后將該對象存入集合中,這樣就能保證存入集合的對象只會有一種類型,否則會在編譯期間報錯。

 

3.stack:滿足“先入先出”的原則,就是堆棧中最先壓入的對象要最先取出。

 

4.ArrayList與LinkedList比較:按順序遍歷集合的元素與插入與刪除操作則LinkedList效率高,而隨機訪問集合中的元素則ArrayList效率高。

 

5.HashSet與ArraySet,我們默認選擇HashSet,一樣在Map的選擇中,我們優先選擇HashMap

 

6.java中提供了兩個靜態類來對數組或列表進行排列和搜索,用於數組的是Arrays,用於列表的是Collections,Collections中有個控制列表等集合不可修改的屬性,這個還是蠻重要的,這樣我們可以將一個容器設為private,然后寫一個方法是來返回一個不可修改的容器類句柄,這樣我們就可以保證用戶不能修改容器內的元素,而在該類中還是可以修改的。還有一個靜態方法是控制容器類同步的,叫synchronizedCollection,

 

7.關鍵字Instanceof告訴我們對象是不是屬於一個特定類型的的實例,返回值是boolean值,如if(x instanceof dog){(dog)x.bark()};

 

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM