1. 程式人生 > >Java程式設計思想 第一章:物件導論

Java程式設計思想 第一章:物件導論

1.1 抽象過程

面嚮物件語言的基本特性:

  1. 萬物皆為物件:理論上講,我們可以抽取一個待解決問題中的任何概念化構件(狗、建築、服務)等,將其表示為程式中的物件。
  2. 程式是物件的集合,它們通過傳送訊息來告知彼此所要做的通俗來說,一個程式是一些物件的集合體,程式之間的通訊實際是物件與物件之間的通訊,要想進行通訊,就必須要傳送一條訊息。更確切的說,我們可以把訊息理解為是對物件的某個特定方法的請求。
  3. 每個物件都有自己的由其他物件所構成的儲存。換句話說就是一個物件可能由其他多個物件共同建立。
  4. 每個物件都擁有其型別。型別是用來區分不同物件的特性,也就是可以傳送什麼樣的訊息給它。
  5. 某一特定型別的所有物件都可以接收同樣的訊息這裡是說物件之間資訊互動的關係。如果一個“圓形”物件也是一個“幾何形”物件,那麼這個“圓形“物件一定也能接收發給”幾何形”物件的訊息。

物件具有狀態、行為和標識,每一個物件都可以擁有內部資料和方法,資料表示狀態,方法產生行為,並且每一個物件都可以唯一的與其他物件分開。擁有相同型別的物件的集合稱為類。即我們建立物件實際是例項化類的一個物件。

1.2 每個物件都有一個介面

物件之間傳遞訊息時,訊息的接收是通過介面來傳遞的,介面對應著物件內部的一個方法,介面暴露給外部物件,內部方法決定訊息的執行方式。

1.3 每個物件都提供服務

我們可以把物件理解為服務提供者,每一個物件都有它所對應的服務需要提供,因此我們在建立一個物件或者說是構建一個類的時候,要思考能否更大程度的抽象出一個物件,以解決一個實際的問題。

1.4 被隱藏的具體實現

我們將開發人員分為兩種,類建立者和客戶端程式設計師。客戶端程式設計師負責快速準確的編寫客戶端程式。類建立者負責構造類,包括類的屬性和介面、方法,這種類只向客戶端程式設計師暴露必要的部分,而隱藏其他部分,防止客戶端程式設計師對類中重要的資料進行修改以對程式造成重要損失,我們稱作是訪問控制。訪問控制的第一個原因是讓客戶端程式設計師無法接觸他們不該接觸的部分,因為有些內容對程式本身來說很重要但是與應用程式業務沒有關係。另一個原因是便於類建立者在不影響客戶端程式的前提下來修改類內部的私有內容。

Java中訪問控制有三個級別:publicprivateprotected。public顧明思議是公有的,表示由public修飾的內容可以供所有人可見。private為私有的,表示由private修飾的部分只有自己可見。protected與private類似,差別在於繼承類中,子類可以訪問父類中的protected修飾區而無法訪問private修飾區。此外還有預設的訪問許可權,即沒有上述三種修飾的情況下,預設在包內可見,在包外等同於private級別。

1.5 複用具體實現

有些時候一個類並不能完全的被複用到另外一種場景,這時我們需要建立一個新的類,並引入之前的類的物件,引入的物件我們宣告為private級別的成員物件。一個新建的類可以有很多個其它型別的物件,這種方式我們稱為組合。它可以有效的實現我們想要的方式的組合,組合是“has-a”的關係,表明某某類有a物件的屬性。同時,由於組合類的成員變數通常都被修飾為private,所以客戶端程式設計師並不能訪問他們,同時也方便了類建立者在不影響程式功能的前提下修改這些成員變數。

  • 聚合
    在這裡插入圖片描述

1.6 繼承

當我們建立一個類時,如果另一個新類與這個類功能相似,我們仍然需要建立這個新類。解決這個問題的辦法就是繼承。繼承雖然也是一個新類,但是這個類是由基類(俗稱父類)衍生的匯出類(俗稱子類)。子類擁有父類所有非private的物件、屬性、介面,此外可以根據不同的需要增加不同的功能。父類可以有很多個子類,它包含了子類的所有公共部分。如“幾何形”是父類,每一個幾何形都具有尺寸、顏色、位置等,同時每一個幾何形都可以被繪製、擦除和移動。在此基礎上可以匯出它的子類“三角形”、“平行四邊形”等,他們擁有父類的屬性、方法之外還有自己獨特的屬性,例如有的形狀可以被翻轉等。

在這裡插入圖片描述

在這裡插入圖片描述

子類不光繼承了父類的屬性,同時也繼承了父類的方法,也就是說所有發給父類的訊息,都可以發給子類。子類對介面的實現方法可以不改變,即訪問子類的介面實際是與訪問父類相同,當然也可以自己“覆蓋”父類介面的方法,也就是說我和父類使用相同的介面,但是我們做不同的事情。同時如前邊所說,子類也可以自己新增方法來滿足自己的需求。前者不改變或者覆蓋介面的方法,這種我們稱作是“is-a”的關係,因為子類與父類本質的型別沒有發生變化。而後邊這種我們稱作是“is-like-a”,因為在子類中增加了新的方法,所以這種相同的關係並不完全。

  • 覆蓋
  • 向上轉型

1.7 伴隨多型的可互換物件

我們說子類繼承父類,同時繼承了父類的方法,也就是說發給父類的訊息同時能夠發給子類。那麼當我們把子類物件看成泛化的基類物件時,如果有個方法是讓泛化的父類操作自己,那麼編譯器在編譯時不知道該執行哪段程式碼的。一個非面向物件程式的函式呼叫是前期繫結,函式要執行的程式碼在程式執行之前就已經確定了,然而在OOP中,直到程式執行我們才知道哪段程式碼被執行了。所以為了解決訊息執行哪段程式碼的問題,Java使用了後期繫結的概念,使用一小段特殊的程式碼來代替非面向物件中所說的絕對地址呼叫,這段程式碼使用在物件中儲存的資訊來計算方法的地址。比如有個父類Shape和子類Circle、子類Triangle,父類中有如下方法

void doSomething(Shape shape){
    shape.erase();
   //...
    shape.draw();
}

這個方法可以與任意Shape型別的物件互動,如果程式中有它的子類呼叫了該方法

Circle circle = new Circle();
Triangle triangle = new Triangle();
cicle.doSomething();
triangle.doSomething();

編譯對doSomething的呼叫會自動處理,而不必考慮是什麼型別。這裡編譯器將子類看成父類,這個過程稱作向上轉型。這段程式碼並不是說“如果是Cirle就xxx,如果是Triangle就xxx”,而是“你就是個Shape,只管做就好,注意細節問題的正確性”。其中細節問題由編譯器進行處理。

  • 後期繫結
  • 前期繫結
  • 向上轉型

1.8 單根繼承結構

在Java語言中,所有的類都是Object類的子類,擁有著Object類的基本方法。這種單根繼承結構有很大的好處,比如在垃圾回收中可以避免由於不知道物件的型別而無處下手,因為他們都可以使用Object類的方法,並且所有物件都可以很容易的在堆上建立。

1.9 容器

有時候我們並不知道處理一個問題需要多少個物件,或者他們需要存活多久,那麼我們就不知道該怎麼樣儲存這些物件。Java語言中建立了一種物件型別,叫做容器(也叫集合)。這種新的物件型別內部有對其他物件的引用,當你需要的時候你可以很容易的擴充容器的空間來容納物件。Java中提供了多種容器型別,如List(用於儲存序列)、Map(也被稱為關聯陣列,用來建立物件的關聯)、Set(每種物件型別只持有一個)。因為容器中儲存了其他物件的引用,所以根據單根繼承結構,容器中的物件型別都是Obejct型別,這樣很方便其他物件型別進行轉型。但是從Object型別轉到其它特定型別(稱作向下轉型)很容易發生錯誤,所以Java SE5之後引入了泛型的概念,引數傳遞使用一對<>,<>內部可以傳遞任意型別的物件,這便解決了向下轉型帶來的安全隱患。

向下轉型是一個是一個十分危險的操作,除非確定知道所要處理的物件的型別,否則向下轉型幾乎是不安全的。

1.10 物件的建立和生命週期

物件的建立主要有兩種,一種是在程式設計時由程式設計師控制,將物件置於堆疊中或者是靜態區域,這種的好處是知道物件的大小、生命週期。同時也限制了物件的靈活性。另一種是通過new在記憶體堆中動態的建立物件,這種方式的好處是靈活,需要的時候直接在記憶體中建立即可,實現了儲存空間的動態管理。Java中完全採用了動態記憶體的分配方式。

對於生命週期,棧上的生命週期,編譯器可以知道它什麼時候銷燬,並自動回收。而在堆上建立的物件,必須由程式設計師自己指定回收時間,如果沒有指定則會造成記憶體洩漏。Java中提供了垃圾回收機制,可以自動的回收在堆上建立的物件。

  • 堆疊
  • 記憶體堆(heap)

1.11 異常處理:處理錯誤

Java內建了異常處理機制,相當於一條與正確執行並行的路線,當程式發生異常時會執行異常的程式碼。同時,允許程式在異常中進行處理並返回到正確的結果中去。

1.12 併發程式設計

Java與其他語言一樣,提供多執行緒的併發程式設計方式,提高程式執行效率。