天天看點

Java 核心學習——第四章對象與類

對象與類

1、  基本概念

1)  類是同一類事物的抽象描述,對象實這一類事物的某個執行個體的稱謂。類是構造對象的模闆,類構造對象的過程為建立對象執行個體。

2)  執行個體域:對象中的資料[C++ 稱成員變量];

3)  方法:操作資料的過程[C++ 稱成員函數];

4)  狀态:每個特定的對象執行個體都有一組特定執行個體域值,這些值的集合描述了對象的目前特征資訊, 這就是對象的狀态;

5)  封裝是對象隐藏執行個體域的關鍵,是面向對象程式設計的一個重要特點。

6)  對象的三個主要特性

A)      對象的行為(behavior)——可以對對象施加哪些行為;

B)      對象的狀态(state)——當在對象上施加某一個/一些行為之後, 對象如何響應/變化;

C)      對象辨別(identity)——如何區分具有相同行為與狀态的不同對象;

7)  類之間的關系

A) 依賴(dependency)("uses -a”)A依賴B, 就表示B可以被A使用;盡量不要兩個類之間互相依賴;

B) 聚合(aggregation)("has -a”)A 聚合B,就表示B是A構成的一部分;

C) 繼承(inheritance)("is-a”)A繼承自B,就表示A是B的一種特例;

2、  對象和對象變量

1)  一個對象變量并沒有實際包含一個對象,而僅僅是一個對象的引用。Java中任何對象變量的值都是對存儲在另外一個地方(堆記憶體區)的一個對象的引用[注:這與C++中的引用是不同的,C++中的任何真實類型都可以有引用,Java中對象的變量才是對象的引用, C++ 中引用類型變量必須指派為一個位址,并且不能為空,Java中的對象引用可以為null ];

2)  new 操作傳回值也是對象的一個引用;

3)  對象變量可以顯示設定為null,表示這個對象變量沒有引用任何對象;

4)  Java中所有對象都存儲在堆中;

5)  當一個對象包含另一個對象變量時,這個變量依然包含着指向另外一個堆對象的指針;

3、  方法

1)  更改其方法(mutator method), 對執行個體域做出修改的方法;

2)  通路器方法(accessor method),僅通路執行個體域而不進行修改[注:C++ 中通路器方法後面增加const,java中通路器方法和更改器方法在文法上沒有差別], 通路器方法通常以get開頭;

4、  類

1)  類編寫風格:首先構造器方法, 共有方法, 私有方法, 域(資料);

2)  一個源檔案中,隻能有一個公有類,并且檔案名與公有類名完全相同, 但是可以包含多個非公有類;

3)  類中資料域通常用private修飾,不建議使用public修飾,不破壞封裝原則;

5、  構造器

1)  構造器方法名必須與類名相同;

2)  構造器方法沒有傳回類型;

3)  構造器方法總是伴随new操作符的執行被調用(原因:Java對象都在堆中構造)[注:C++中可以構造堆對象通過new操作調用構造器,也可以定義棧中定義一個對象,自動調用構造器],而不能對一個已經存在的對象調用構造器方法重新設定對象的資料域,;

4)  每個類可以有多個構造器方法, 構造器方法可以有0個、1個或多個參數;沒有參數的構造器稱之為預設構造器,

5)  不要再構造器方法中定義與域資料重名的變量,否則在構造器方法中将隐藏了域資料變量;

6、  隐式參數與顯示參數

1)  對象的方法調用的時候,第一個參數為隐式參數,其參數為調用方法前面的對象;

2)  位于方法的括号中的參數為顯示參數;

3)  每個方法中this為隐式參數;

7、  方法定義

Java中方法都定義在類的内部,而C++ 中方法可以定義在類定義内部預設為inline,也可以定義外類外部;Java中方法是否為inline,不能由程式員設定,Java虛拟機會監視方法的調用情況、方法的簡潔度和是否被重載決定是否進行優化(inline);

8、  封裝的優點

1)  方法為接口,接口被使用者調用,隐藏内部對資料域操作的實作,實作修改了,不影響調用者代碼;

2)  更改器方法可以執行錯誤檢查, 然而直接對資料域指派就改變了對象的狀态;

3)  不要設計傳回對象引用的通路器方法,否則調用者可以通過對象的引用修改對象的狀态,建議在通路器内克隆一個對象傳回[Java中所有類都是Object的子類,Object 擁有clone方法];

9、  基于類的通路權限

1)  一個方法可以通路所屬類的所有對象的私有資料;通路可以方法所屬類的私有特性(資料|方法),而不僅僅限于隐式參數的私有特性;

2)  Final修飾執行個體域表示執行個體域在對象構造之後, 不會再被改變, final修飾的通常是基本資料類型或者不可變類(類中的每個方法都不可以改變對象,這樣的類稱為不可變類)的域;

3)  對象通路器如果傳回final修飾的執行個體域可變類對象,但是調用者可以通過傳回的對象調用對象的修改器, 這樣導緻對象被改變,這樣導緻破壞封裝,如果要傳回可變類,應該在通路器中構造新對象傳回. [C++中常量對象隻能調用對象的通路器,而不能調用修改器]

例如:

class Employee

{

               public Address getAddr()

               {

                  return addr;

               }

               private String name;

               private double salary;

      private final Address addr;

}

         class Address

         {

           public void setCode(String code)

           {

              this.code = code;

           }

           private String city;

           private String home;

           private String code;

         }

       Employee emp = new Employee(…);

       emp.getAddr().setCode(“adfad”);

10、  靜态域和靜态方法

1、  域被定義成靜态的(static),表示所有對象都共用靜态域,而非靜态域則是每個對象都有。Java和C++ 中靜态方法和靜态域在功能上相同,通路方法不同,Java中通過[類名.方法/類名.域]通路,但是C++中用[類名::方法/類名::域]通路;

2、  Factory方法, NumberFormat類使用factory方法産生不同風格的對象;

11、  方法參數[C++中有傳值和傳引用]

1)  一個方法不能修改一個基本資料類型的參數;

2)  一個方法可以修改一個對象參數的狀态;

3)  一個方法不能實作讓對象引用一個新的對象;

12、  對象初始化

1)  預設構造器是指沒有參數的構造器,如果編寫一個類的時候,沒有提供一個構造器,系統會提供一個預設構造器。 預設構造器将所有的執行個體域設定為預設值。數值型設定為0,布爾型設定為false, 所有對象變量将設定為null。如果類中提供了至少一個構造器,系統将不會提供預設構造器。

2)  顯示初始化域, 在執行構造器之前對域進行指派(聲明的時候指派)[C++中不能初始化執行個體域,但是有初始化清單,在執行構造器的時候, 在執行其方法實體前,Java沒有子對象,隻有子對象引用,是以java不需要初始化清單]。

3)  調用另一個構造器,對于同一個類中,一個構造器需要調用另一個構造器,用this(參數清單)[C++中,this指針不能作為構造器使用,也不能在一個構造器中調用另一個構造器],構造器中調用另一個構造器必須是該方法中的第一個語句。

4)  初始化塊,用{} 在類中定義一個語句塊,即不是方法定義,也不是資料定義;初始化塊可以在對資料域進行改變, 它在構造器執行之後才執行的。

5)  對于靜态域的初始化,不能在構造器中執行,可以在靜态初始化塊中執行,靜态初始化塊的定義如:static{};靜态初始化塊在類第一次加載的時候執行。

13、  析構

Java中沒有析構器[ C++有析構函數, 在對象生命周期結束時調用],Java中有垃圾回收機制,是以不需要釋放記憶體, 對于其他資源,建議在不在使用的時候, 立即釋放。Java中可以為一個類添加finalize方法, 該方法将在垃圾回收器清除對象之前調用,但是Java中垃圾回收時機使用者不能确定,是以不建議使用。

14、  包

1)        Java中使用包(packet)将類組織起來。借助于包可以友善的組織自己的代碼, 并将自己的代碼與别人提供的代碼庫分開管理。強調一下,這裡說的是組織, 而不是簡單的存放, 組織也表示了代碼結構組織。

2)        使用包的另一個優點,確定類名唯一性。

3)        包命名規則, Sun建議使用公司internet域名的逆序作為包名,不同項目可以增加子包。

4)        一個類可以使用所屬的包中的所有類,以及其他包中的公有類(public class)

5)        導入

A) 在每個類名稱前面帶完整的包名, 但是這樣使得代碼難看, 可以使用import導入某個包或者包中的類,import語句位于源檔案的頂部(packet語句之後);

B) 導入是可以通過 import包名.*導入所有類,但是不建議這樣使用,容易造成編譯的時候類名稱沖突導緻編譯失敗(包的定位是編譯器的工作), 但是Java位元組碼标示類是通過完整的包名引用的;

C) Java的import與C++ 的#inlucde不同, C++中#include将外部特性的聲明加載進來,C++編譯器無法檢視任何檔案的内部;Java編譯器可以檢視其它檔案的内部,隻要告訴編譯器從哪裡查找。C++中,命名空間(namespace)與Java中的包機制類似, package與import語句類似于C++中的namespace和using 指令。

D) 靜态導入, Java SE5.0開始, import語句不僅可以導入類,還可以導入靜态方法和靜态域功能, 還可以導入特定的方法或域。

E)  Java.lang是預設導入的。

6)        包定義,要想将類加入某個包中,就必須将包的名字放在源檔案的開頭,包中定義類的代碼之前。 如果沒有在源檔案中放置package語句,這個源檔案中的類就被放置在一個預設包中。

7)        包作用域,public修飾的部分,可以被任意類使用;private修飾的部分隻能被定義它們的類使用;沒有指定public或private的,可被同一個包中的所有方法通路。對于類如果隻在包中通路,可以不指定修飾符,但是資料域最好指定修飾符。

15、  類設計技巧

1)  一定将資料設計為私有, 不能破壞封裝;

2)  一定要對資料初始化, Java不對局部變量進行初始化, 但是會對對象的執行個體域進行初始化。最好不要依賴系統的預設值。

3)  不要在類中使用過多的基本資料類型;

4)  不是所有的域都需要獨立的通路器和更改器;

5)  使用标準格式進行類定義,并保持一緻的風格;

A) 公有通路特性部分;

B) 包作用域通路特性部分;

C) 私有通路特性部分;

D) 執行個體方法;

E)  靜态方法;

F)  執行個體域;

G) 靜态執行個體域;

6)  将職責過多的類分解成不同的類;

7)  類名和方法名能夠展現它們的職責;類名通常是一個名詞,可以用動名詞/形容詞+ 名詞