一、面對(duì)對(duì)象程序設(shè)計(jì)概述
1.類
? ? 類是構(gòu)造對(duì)象的模板。由類構(gòu)造對(duì)象的過(guò)程稱為創(chuàng)建類的實(shí)例。
? ? 封裝(即隱藏?cái)?shù)據(jù)):從形式上看,封裝不過(guò)是將數(shù)據(jù)和行為組合在一個(gè)包中,并對(duì)對(duì)象的使用者隱藏了數(shù)據(jù)的實(shí)現(xiàn)方式。
? ? 實(shí)例域:對(duì)象中的數(shù)據(jù)。
? ? 方法:操作數(shù)據(jù)的過(guò)程。
? ? 實(shí)現(xiàn)封裝的關(guān)鍵在于絕對(duì)不能讓類中的方法直接的訪問(wèn)其他類的實(shí)例。程序僅通過(guò)對(duì)象的方法與對(duì)象的數(shù)據(jù)進(jìn)行交互。封裝給對(duì)象給予了“黑盒”特性,這是提高重用性與可靠性的關(guān)鍵。
? ? 可以通過(guò)擴(kuò)展一個(gè)類來(lái)建立另外一個(gè)新的類。Java中,所有的繼承Object類。
2.對(duì)象
? ? 對(duì)象的三個(gè)主要特性:對(duì)象的行為、對(duì)象的狀態(tài)、對(duì)象標(biāo)識(shí)。
3.類之間的關(guān)系
? ? 繼承、實(shí)現(xiàn)、依賴、關(guān)聯(lián)、聚合、組合的聯(lián)系與區(qū)別 - 簡(jiǎn)書
? ? 依賴(“uses-a"):如果一個(gè)類的方法操縱另一個(gè)類的對(duì)象,我們就說(shuō)一個(gè)類依賴于另一個(gè)類。
? ? 聚合(”has-a"):聚合關(guān)系意味著類A的對(duì)象包含類B的對(duì)象。
? ? 繼承(“is-a"):是一種用于表示特殊與一般的關(guān)系。一般而言,如果類A擴(kuò)展類B,類A不但包含從類B繼承的方法,還會(huì)擁有一些額外的功能。
二、使用預(yù)定義類
1.對(duì)象與對(duì)象變量
? ?要想使用對(duì)象,就必須首先構(gòu)造對(duì)象,并指定其初始狀態(tài)。然后,對(duì)對(duì)象應(yīng)用方法。
? ?在Java中,使用構(gòu)造器構(gòu)造新實(shí)例。構(gòu)造器是一種特殊的方法,用來(lái)構(gòu)造并初始化對(duì)象。構(gòu)造器的名字應(yīng)該與類名相同。
? ?想要構(gòu)造一個(gè)Date對(duì)象,需要在構(gòu)造器前面加上new操作符,如 new Date()。
? ?可以將對(duì)象傳遞給一個(gè)方法: System.out.println(new Date())。
? ?也可以將一個(gè)方法應(yīng)用與剛剛創(chuàng)建的對(duì)象:String s= new Date().toString()。
? ?通常,希望構(gòu)造的對(duì)象可以多次使用,因此需要將對(duì)象存放在一個(gè)變量中:Date birthday=new Date()。
? ?一個(gè)對(duì)象變量并沒(méi)有實(shí)際包含一個(gè)對(duì)象,而僅僅引用了一個(gè)對(duì)象。(任何對(duì)象變量的值都是對(duì)存儲(chǔ)在另一個(gè)地方的一個(gè)對(duì)象的引用)。
? ?局部變量不會(huì)自動(dòng)地初始化為null,而必須通過(guò)調(diào)用new或?qū)⑺鼈冊(cè)O(shè)置為null進(jìn)行初始化。
2.LocalDate類?
? 不要使用構(gòu)造器來(lái)構(gòu)造LocalDate對(duì)象,實(shí)際上,應(yīng)當(dāng)使用靜態(tài)工廠方法代表你調(diào)用構(gòu)造器:LocalDate.now()。?
? 一旦有了一個(gè)LocalDate對(duì)象,可以用方法getYear,getMonthValue,getDayOfMonth得到年、月、日。
? 注意LocalDate類與Date類的區(qū)別。
3.更改器方法與訪問(wèn)器方法
? ?訪問(wèn)器方法:只訪問(wèn)對(duì)象而不修改對(duì)象的方法。
? ?更改器方法:不僅訪問(wèn)對(duì)象而且修改對(duì)象的方法。
三、用戶自定義類
?在一個(gè)源文件中,只能有一個(gè)公有類,但可以有任意數(shù)目的非公有類。
1.構(gòu)造器
? 構(gòu)造器總是伴隨著new操作符的執(zhí)行被調(diào)用,而不能對(duì)一個(gè)已經(jīng)存在的對(duì)象調(diào)用構(gòu)造器來(lái)達(dá)到重新設(shè)置實(shí)例域的目的。? ??
? ?構(gòu)造器與類同名
? ?每個(gè)類可以有一個(gè)以上的構(gòu)造器
? ?構(gòu)造器可以有0個(gè)、1個(gè)或多個(gè)參數(shù)
? ?構(gòu)造器沒(méi)有返回值
? ?構(gòu)造器總是伴隨著new操作一起調(diào)用
?請(qǐng)注意:不要在構(gòu)造器中定義與實(shí)例域重名的局部變量
2.隱式參數(shù)與顯式參數(shù)
? ? 顯式參數(shù)是明顯地列在方法聲明中,隱式參數(shù)沒(méi)有出現(xiàn)在方法聲明中,在每一個(gè)方法中this表示隱式參數(shù)。
3.封裝的優(yōu)點(diǎn)
? 在有些時(shí)候,需要獲得或設(shè)置實(shí)例域的值,因此,需要提供下面三項(xiàng)內(nèi)容:
? ? ? ?一個(gè)私有的數(shù)據(jù)域
? ? ? ?一個(gè)公有的域訪問(wèn)器方法
? ? ? ?一個(gè)公有的域更改器方法
? ?封裝的優(yōu)點(diǎn):
? ? 1.可以改變內(nèi)部實(shí)現(xiàn),除了該類的方法之外,不會(huì)影響其他代碼。
? ? 2.更改器方法可以執(zhí)行錯(cuò)誤檢查,然而直接對(duì)域進(jìn)行賦值將不會(huì)進(jìn)行這些處理。例如:setSalary方法可以檢查薪金是否小于0。
? ?注意:不要編寫返回引用可變對(duì)象的訪問(wèn)器方法
?4.基于類的訪問(wèn)權(quán)限
? ? 方法可以訪問(wèn)所屬類的私有特性,而不僅限于訪問(wèn)隱式參數(shù)的私有特性。
?5.final實(shí)例域
? ? 可以將實(shí)例域定義為final。構(gòu)建對(duì)象時(shí)必須初始化這樣的域。也就是說(shuō),必須確保在每一個(gè)構(gòu)造器執(zhí)行之后,這個(gè)域的值被設(shè)置,并且在后面的操作中,不能夠?qū)λM(jìn)行修改。?即沒(méi)有setName方法。
? ? final修飾符大都應(yīng)用于基本類型域,或不可變類的域(如果類中的每個(gè)方法都不會(huì)改變其對(duì)象,這種類就是不可變類。如String)
? ? 對(duì)于可變的類,使用final修飾符可能會(huì)對(duì)讀者造成混亂,如:
? ? private?final StringBuilder?a;
? ? 在構(gòu)造器中會(huì)初始化為
? ? a=new StringBuilder();
? ? final關(guān)鍵字只是表示存儲(chǔ)在a變量中的對(duì)象引用不會(huì)再指示其他StringBuilder對(duì)象,不過(guò)這個(gè)對(duì)象可以更改。如:
? ? a.append(LocalDate.now()+":Gikd star!")
四、靜態(tài)域與靜態(tài)方法
1.靜態(tài)域(類域)
? ?如果將域定義為static,則每個(gè)類只有一個(gè)這樣的靜態(tài)域,而對(duì)于實(shí)例域則每個(gè)對(duì)象都有一份拷貝。即每個(gè)對(duì)象擁有自己的實(shí)例域,但共享同一個(gè)靜態(tài)域。即使沒(méi)有對(duì)象,靜態(tài)域也存在,它屬于類,而不屬于任何獨(dú)立的對(duì)象。
2.靜態(tài)常量
? ?靜態(tài)變量使用得比較少,靜態(tài)常量卻使用得比較多。例如在Math?類中定義一個(gè)PI,另一個(gè)使用比較多的靜態(tài)常量是System.out。
3.靜態(tài)方法
? ?靜態(tài)方法是一種不能向?qū)ο髮?shí)施操作的方法。
? ?靜態(tài)方法不能訪問(wèn)對(duì)象的實(shí)例域,只能訪問(wèn)自身類中的靜態(tài)域。
? ?可以認(rèn)為靜態(tài)方法是沒(méi)有this參數(shù)的方法
? ?可以使用對(duì)象調(diào)用靜態(tài)方法,但建議使用類名.方法名的方式代替對(duì)象引用.方法名的方式調(diào)用方法。
? 下面兩種情況下使用靜態(tài)方法:
? 一個(gè)方法不需要訪問(wèn)對(duì)象狀態(tài),其所需參數(shù)都是通過(guò)顯式參數(shù)提供(例如:Math.pow)。
? 一個(gè)方法只需要訪問(wèn)類的靜態(tài)域(例如:Employee.getNextId)。
?4.工廠方法
? ? 靜態(tài)方法還有另外一種常見(jiàn)的用途,類似LocalDate和NumberFormat的類使用靜態(tài)工廠方法來(lái)構(gòu)造對(duì)象。
? ? 為什么考慮用工廠方法替代構(gòu)造方法?可參考下方
? ? 關(guān)于 Java 的靜態(tài)工廠方法,看這一篇就夠了! - 簡(jiǎn)書
? ? 考慮使用靜態(tài)工廠方法替代構(gòu)造方法 - 風(fēng)一樣的碼農(nóng) - 博客園
?5.main方法
? ? ?main方法不對(duì)任何對(duì)象進(jìn)行操作。事實(shí)上,在啟動(dòng)程序時(shí)還沒(méi)有任何一個(gè)對(duì)象。靜態(tài)的main方法將執(zhí)行并創(chuàng)建程序所需要的對(duì)象。
?五、方法參數(shù)
? ? ?Java 程序設(shè)計(jì)語(yǔ)言總是采用按值調(diào)用。也就是說(shuō),方法得到的是所有參數(shù)值的一個(gè)拷貝,特別是,方法不能修改傳遞給它的任何參數(shù)變量的內(nèi)容。
? ? ?總結(jié)Java中方法參數(shù)的使用情況:
? ? ?一個(gè)方法不能修改一個(gè)基本數(shù)據(jù)類型的參數(shù)(即數(shù)值型或布爾型)。
? ? ?一個(gè)方法可以改變一個(gè)對(duì)象參數(shù)的狀態(tài)。
? ? ?一個(gè)方法不能讓對(duì)象參數(shù)引用一個(gè)新的對(duì)象。
? 詳見(jiàn):java按值與按引用調(diào)用 – 木子de!小屋屋
?六、對(duì)象構(gòu)造
?1.重載
? ?如果多個(gè)方法有相同的名字、不同的參數(shù),便產(chǎn)生了重載。
? ?Java允許重載任何方法,而不只是構(gòu)造器方法。
? ?要完整的描述一個(gè)方法,需要指出方法名以及參數(shù)類型。這叫做方法的簽名。如indexOf(int,int)是簽名
? ?返回類型不是方法簽名的一部分,也就是說(shuō),不能有兩個(gè)名字相同、參數(shù)類型也相同卻返回不同類型值的方法。
2.默認(rèn)域初始化
? ?如果在構(gòu)造器中沒(méi)有顯式地給域賦予初值,那么就會(huì)被自動(dòng)地賦為默認(rèn)值,數(shù)值為0、布爾值為false、對(duì)象引用為null(這是域與局部變量地主要不同點(diǎn),必須明確地初始化方法中的局部變量)
3.無(wú)參數(shù)的構(gòu)造器
? ?如果在編寫一個(gè)類時(shí)沒(méi)有編寫構(gòu)造器,那么系統(tǒng)就會(huì)提供一個(gè)無(wú)參數(shù)構(gòu)造器。這個(gè)構(gòu)造器將所有的實(shí)例域設(shè)置為默認(rèn)值。
? ?如果類中提供了至少一個(gè)構(gòu)造器,但是沒(méi)有提供無(wú)參數(shù)的構(gòu)造器,則在構(gòu)造對(duì)象時(shí)如果沒(méi)有提供參數(shù)就會(huì)被視為不合法。
? ?即僅當(dāng)類沒(méi)有提供任何構(gòu)造器的時(shí)候,系統(tǒng)才會(huì)提供一個(gè)默認(rèn)的構(gòu)造器。
4.顯示域初始化
? ?可以在類定義中,直接將一個(gè)值賦給任何域,在執(zhí)行構(gòu)造器之前,先執(zhí)行賦值操作。當(dāng)一個(gè)類的所有構(gòu)造器都希望把相同的值賦予某個(gè)特定的實(shí)例域時(shí),使用這種方法特別有用。
? ?初始值不一定是常量值,可以調(diào)用方法對(duì)域進(jìn)行初始化。
5.調(diào)用另一個(gè)構(gòu)造器
? ?如果構(gòu)造器的第一個(gè)語(yǔ)句形如this(...),這個(gè)構(gòu)造器將調(diào)用同一個(gè)類的另一個(gè)構(gòu)造器。
? ?采用這種方式使用this關(guān)鍵字非常有用,這樣對(duì)公共的構(gòu)造器代碼部分之編寫一次。
6.初始化塊
? ?Java 中三種初始化域的方法: 1.在構(gòu)造器中設(shè)置 2.在聲明中賦值 3.初始化塊
? ?只要構(gòu)造類的對(duì)象,初始化塊就會(huì)被執(zhí)行。首先運(yùn)行初始化塊,然后才運(yùn)行構(gòu)造器的主體部分。
? ?建議將初始化塊放在域定義之后。
? ?在類第一次加載的時(shí)候,將會(huì)進(jìn)行靜態(tài)域的初始化。所有的靜態(tài)初始化語(yǔ)句以及靜態(tài)初始化塊都將依照類定義的順序執(zhí)行。
7.對(duì)象構(gòu)析與finalize方法
? ?可以為任何一個(gè)類添加finalize方法。finalize方法將在垃圾回收器清除對(duì)象之前調(diào)用。在實(shí)際應(yīng)用中,不要依賴于使用finalize方法回收任何短缺的資源。
? ?如果某個(gè)資源需要在使用完畢后立刻被關(guān)閉,那么就需要人工來(lái)管理。對(duì)象用完時(shí)可以應(yīng)用一個(gè)close方法來(lái)完成相應(yīng)的清理操作。
七、類設(shè)計(jì)技巧
? 一定要保證數(shù)據(jù)私有
? 一定要對(duì)數(shù)據(jù)初始化
? 不要在類中使用過(guò)多的基本類型
? 不是所有的域都需要獨(dú)立的域訪問(wèn)器和域更改器
? 將職責(zé)過(guò)多的類進(jìn)行分解
? 類名和方法名要能夠體現(xiàn)它們的職責(zé)
? 優(yōu)先使用不可變的類