摘要:而面向對象則是向程序員提供表示問題空間中元素的工具,我們將問題空間中的元素及其在解空間中的表示稱為對象。為什么要把對象看作是服務提供者呢這是將問題分解為對象集合的一種合理方式。職能太多,可能會導致對象的內聚性降低。在試圖將子類對象當作其基類
計算機是頭腦延伸的工具,是一種不同類型的表達媒體。本文以背景性的和補充性的材料,介紹包括開發方法概述在內的面向對象程序設計(Object-oriented Programming,OOP)的基本概念。
本文通過概念+代碼的方式,來幫助讀者了解面向對象程序設計的全貌。
抽象過程機器模型:位于解空間內,是對問題建模的地方;可以這樣理解,匯編語言和命令式語言,在解決問題時要基于計算機的架構;因此架構限定了解決方案,所以說機器模型是解空間。
實際待解決問題:問題空間,是問題存在的地方
抽象的類型和質量,決定了人們所能夠解決的問題的復雜性。抽象的類型指的是“所抽象的是什么”。一種是在機器模型和實際待解決問題的模型之間建立聯系的抽象;另一種是只針對待解決問題建模。而面向對象則是向程序員提供表示問題空間中元素的工具,我們將問題空間中的元素及其在解空間中的表示稱為“對象”。
萬物皆是對象;
程序是對象的集合,對象間方法的調用是程序運行的基本表現;
對象可以包含其他對象;
每個對象都擁有其特定的類型;
某一特定類型的所有對象都可以接收同樣的方法調用;
什么是對象?對象具有狀態、行為和標識。每一個對象都可以擁有內部數據和方法,并且可以唯一的與其他對象區分開來每個對象都應該都歸屬于一個類或接口
對象:具有狀態、行為和標識的實體。如銀行存款賬戶是一個類,那么具體的每個人的銀行存款賬戶就是這個類目下的對象。
類:可以看作類型來考慮。比如說鳥類,是動物中的其中一種類型。
所有的對象都是唯一的,但同時具有相同的特性和行為的對象也都歸屬于某個特定的類。
類在Java中用關鍵詞class表示。每個類的對象都具有某種共性和個性,如銀行存款賬戶,每個賬戶中都有余額的屬性,但每個賬戶中的余額又不同。在實際中,面向對象程序設計語言都用class關鍵字來表示數據類型,換而言之,每一個類都是一個數據類型。程序員可以自由地添加新的類(數據類型)來擴展編程語言,對實際問題進行處理。
面向對象的挑戰之一,就是在問題空間的元素和解空間的對象之間創建一對一的映射。
獲取有用對象,必須以某種方式對對象進行請求,使對象完成各種任務。類型決定接口,而接口決定對象能滿足的請求。就比如鳥類型,其提供的接口有飛翔,因此其能滿足飛翔的請求。在接口確定了某一特定對象能夠發出的請求后,接口的實現掌控著請求的具體行為的展現方式。在類型中,每一個可能的請求都有一個方法與之關聯,當向對象發送請求時,與之關聯的方法就會被調用。
以下代碼是獲取一個對象并調用其中的方法實例(你可以暫時不用理解,只需要知道形式即可,后面再反過來看就好)
public class Light { //開燈 public void on() { System.out.println("Light is on!"); } //關燈 public void off() { System.out.println("Light is off!"); } //這里是獲取一個對象并調用其中方法的實例 public static void main(String [] args) { //這里是核心代碼,開燈操作 Light lt = new Light(); lt.on(); } }
### 對象是服務提供者
程序通過調用其他對象提供的服務來向用戶提供服務。程序員的目標就是去創建(或者最好是從現有的代碼庫中尋找)能夠提供解決問題所需服務的一系列對象。
為什么要把對象看作是服務提供者呢?
這是將問題分解為對象集合的一種合理方式。比如說,你正在創建一個簿記系統,那么,這個系統可以拆分為:我需要一個包括了預定義的簿記輸入屏幕的對象、一個執行簿記計算的對象集合以及一個處理在不同的打印機上打印支票和開發票的對象。
它有助于提高對象的內聚性。就像上面所定義的簿記系統,每個對象都可以很好地完成一項任務,但是它并不試圖做更多的事情。職能太多,可能會導致對象的內聚性降低。簡而言之,每個對象只做它該做的事。
程序訪問權限控制將程序開發人員按照角色劃分為類創建者和客戶端程序員。類創建者創建新的數據類型,而客戶端程序員在其應用中使用類創建者創建的新數據類型。如此一來,客戶端程序員的主要目的就是收集各種用來實現快速應用開發的類;而類創建者的目的則是構建類,并向客戶端程序員暴露必須的部分。
為什么類創建者需要對類的某些部分進行隱藏呢?或者說,為什么需要進行訪問權限控制呢?
讓客戶端程序員無法觸及他們不該觸及的部分,讓客戶端程序員分清楚,哪些東西對他們來說是必須的,哪些是可以忽略的。
允許庫設計者可以改變類內部的工作方式而不用擔心會影響到客戶端程序員。因為對客戶端程序員所提供的那一部分可見的內容總是不變的,而庫設計者改變的是其中隱藏的部分。
修飾符 | 類內部 | 同包 | 子類 | 任何地方 |
---|---|---|---|---|
private | √ | × | × | × |
無 | √ | √ | × | × |
protected | √ | √ | √ | × |
public | √ | √ | √ | √ |
public:可以修飾外部類、屬性、方法;
protected:只能修飾屬性和方法;
private:只能修飾屬性、方法、內部類;
復用具體實現代碼復用是面向對象程序設計語言所提供的最了不起的優點之一。
代碼復用的基本方式:
直接使用該類的一個對象;
可以將某個類的一個對象置于一個新類中,作為新類的成員出現;
類之家的關系關系是指事物之間存在單向或者相互的作用力或者影響力的狀態。
在兩個類之間存在有關系和沒關系兩種情況,在有關系的情況下,其關系包括以下六種類型
類關系 | 英文名 | 描述 | 強權方 | UML圖表示 | 示例說明 |
---|---|---|---|---|---|
繼承 | extends | 父類與子類之間的關系:is-a | 父類 | 空心三角+實線,空心三角指向父類 | 鳥是動物 |
實現 | implements | 接口與實現類之間的關系:can-do | 接口 | 空心三角+虛線,空心三角指向接口 | 鳥實現了飛翔的接口 |
組合 | composition | 比聚合更強的關系:contains-a | 整體 | 實心菱形+實線,實心菱形指向整體 | 人類的頭和身體是強組合關系 |
聚合 | aggregation | 暫時組裝的關系:has-a | 組裝方 | 空心菱形+實線,空心菱形指向組裝方 | 狗和牽狗的繩子是聚合關系 |
依賴 | dependency | 一個類依賴于另一個類:depends-a | 被依賴方 | 箭頭+虛線,箭頭指向被依賴方 | 人喂小狗,小狗是喂這個動作的被依賴方 |
關聯 | association | 類與類之間存在互相平等的使用關系:links-a | 平等 | 實線 | 人與信用卡的關系,人用信用卡,信用卡可以讀取個人信息 |
以現有類為基礎,復制它,然后通過添加和修改這個副本來創建新類。當源類發生變化時,被修改的副本也會反應出這種變動。生物學中對科目的定義,用于解釋繼承關系再恰當不過。
父類:又稱源類、基類、超類;
子類:又稱導出類、繼承類;
父類和子類之間的類型層次結構同時體現了他們之間的相似性和差異性。當繼承現有類型時,也就創造了新的類型,同時子類又歸屬于父類的類型。這個新的類型不僅包括現有類型的所有成員,而且更重要的是它復制了父類的接口,這意味著所有對父類對象的調用同時可可以對子類對象發起,這遵循了編程原則之一的里氏替換原則。
如果只是簡單地繼承一個類而不做其他任何事情,那么在父類接口中的方法將會直接繼承到子類中。當需要使父類和子類產生差異時,有以下兩種方式:
直接在子類中添加新的方法;在采用該種方案時需要仔細考慮是否存在父類也需要這些額外方法的可能性。
覆寫父類中的某個方法;該種方案需要在子類中定義與父類需覆寫方法同名、同返回值類型、同方法參數類型的方法。
那么繼承是否應該只覆寫父類的方法呢?
如果繼承只覆寫了父類的方法,那么子類對象可以完全替代父類對象,這通常稱之為替代原則,在這種情況下的類關系稱為is-a;但有時又的確需要在子類中添加新的接口,這種情況下父類無法訪問新添加的接口,這種情況下類關系為is-like-a,這時這種父類與子類之間的關系,被視為非存粹替代
多態在處理類層次關系的時候,如果把任意一個特定類型的對象可以當作其基類對象來對待,就使得人們可以編寫出不依賴于特定類型的代碼。
前期綁定:編譯器將產生對一個具體函數名字的調用,而在運行時需要將這個調用解析到將要被執行的代碼的絕對地址(意味著運行前就需要知道具體代碼的位置)。
后期綁定:編譯器只確保調用的方法存在,而且調用參數和返回值類型正確;在運行時,通過特殊代碼,解析具體將要執行的代碼的具體位置。
通過導出新的子類而輕松擴展設計的能力,是對改動進行封裝的基本方式之一。
在試圖將子類對象當作其基類對象來看待時,需要解決的一個問題是:編譯器無法精確地了解哪一段代碼將會被執行。在OOP程序設計中,程序直到運行時才能夠確定代碼的位置。
OOP程序設計語言使用了后期綁定的概念:編譯器確保調用方法的存在,并對調用參數和返回值執行類型檢查,但并不知道將被執行的確切代碼。Java使用一小段特殊的代碼來替代絕對地址調用,這段特殊代碼用來計算方法體的具體位置。Java默認是動態綁定的。
把子類對象看作父類對象的過程,稱作向上轉型。原因是在類圖中,父類總是位于類圖的頂部,把子類對象視為父類對象,即將子類類型向上推導。
單根繼承Java中所有的類最終都繼承自單一的基類:Object
單根繼承結構保證所有對象都具備某些功能。Object是任何類的默認父類,是在哲學方向上繼續寧的延伸思考。
我是誰?getClass()說明本質上是誰,而toString()是當前類的名片。
我從哪里來?Object()構造方法是生產對象的基本方式;clone()是繁殖對象的另一種方式。
我到哪里去?finalize()方法說明了對象的最終歸屬
我是否是獨一無二的?hashCode()和equals()就是判斷與其他元素是否相同的一組方法。
與其他人如何協調?wait()和notify()方法是對象間通信和協作的一組方法。
容器通常來說,如果不知道在解決某個特定問題時需要多少對象,或者他們將存活多久,那么就不可能知道如何存儲這些對象。
在Java標準類庫中提供了大量容器。不同的容器提供了不同類型的接口和外部行為,同時對某些操作具有不同的效率。如List中的ArrayList和LinkedList由于底層實現的不同,具備不同的應用場景。
由于容器只存儲Object,所以將對象引入置入容器時,被向上轉型為Object,在取出類型時會丟失其類型。在一定程度上可以使用向下轉型的方式來獲取其實際類型,但是這樣做存在風險。
package a; import java.util.*; public class Container { public static void main(String [] args) { List list = new ArrayList(); list.add("Hello World!"); list.add(1); //程序運行到這里是不會報錯的,但是執行下面這一步的時候,就會出現異常了 for(Object o : list) { //這一步會出現異常,因為List中存放的不僅僅是String類型,還有Integer類型,向下轉型出現異常 String a = (String) o; System.out.println(a); } } }
那么用什么方式使容器記住這些對象究竟使什么類型呢?解決方案稱為參數化類型,在Java中也稱為泛型。表示方法為一對尖括號,中間包含類型信息。
List
這樣一來,就限定了List中只能存放String類型的對象啦!當然,我們還是能夠通過反射繞過這層驗證,畢竟在編譯后運行時,是去泛型的。
對象的創建和生命周期在使用對象時,最關鍵的問題之一便是他們的生成和銷毀方式。
new Constructor();:通過new關鍵詞向堆中申請內存,通過Constructor來說明類的創建方式。
Java采用動態內存分配的方式。動態方式有個一般性假設:對象趨于變得復雜,所以查找和釋放內存空間的開銷不會對對象的創建造成重大沖擊。動態方式所帶來的更大的靈活性是解決一般化編程問題的要點。
Java提供了被稱為垃圾收集器的機制,用來處理內存釋放問題。垃圾收集器的運行基礎是單根繼承結構和只能在堆上創建對象的特性。
異常處理錯誤處理始終是編程的難題之一。
異常是一種對象,其從出錯點被拋出,并被特定類型的異常處理器所捕獲。異常處理就像與程序正常執行路徑并行的、在錯誤發生時執行的另一條路徑。
異常不能被忽略,它保證一定會在某處得到處理。異常提供了一種從錯誤狀態進行可靠恢復的途徑。Java一開始就內置了異常處理,并強制你必須使用它。它是唯一可接受的錯誤報告方式。
并發編程在計算機編程中,存在著在同一時刻處理多個任務的思想。這些彼此獨立運行的部分稱為線程,同一時刻處理多個任務稱為并發。
在單一處理器中,線程只是一種為單一處理器分配執行時間的手段,換而言之,如果只有一個處理器,那么多線程程序的運行不過是多個任務競爭使用處理器的性能。在多處理器的情況下,實現的才是真正意義上的并發,多處理器并行計算。
多線程同時存在一個隱患,在存在共享資源的時候,可能會造成資源之間的競爭,進而造成死鎖。所以在多線程修改共享資源時,必然在共享資源使用期進行鎖定。
在Java中,JDK1.5后提供了concurrent包支持更好的并發特性。
結語以上是對象導論的一些基本概念,是繼續閱讀后面章節的非必要補充性材料。對于文中的一些代碼段或概念,暫時不理解的,可以先放一放,等后面看完了,再回過來看就恍然大悟了。
下一節將講解對象并寫第一個Java程序。如果你對這些內容不感興趣,想看點更高難度的,歡迎關注我的博客:https://www.cnblogs.com/lurke...;歡迎關注我的微信公眾號JavaCorner
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/77416.html
摘要:開頭正式開啟我入職的里程,現在已是工作了一個星期了,這個星期算是我入職的過渡期,算是知道了學校生活和工作的差距了,總之,盡快習慣這種生活吧。當時是看的廖雪峰的博客自己也用做爬蟲寫過幾篇博客,不過有些是在前人的基礎上寫的。 showImg(https://segmentfault.com/img/remote/1460000010867984); 開頭 2017.08.21 正式開啟我...
摘要:類最基本的作用,在于通過類獲取到相應的對象,在向對象發送消息時以期望對象做某些特定的事情。先導概念引用中一切皆對象,因此采用一個指向對象的引用來操縱對象。對象可以存活于作用域之外。 歡迎各位讀者關注我的微信公眾號,共同探討Java相關技術。生命不止,學習不休! showImg(https://segmentfault.com/img/bVboaBO?w=129&h=129); 也許你慢...
摘要:當我們希望能界定這二者之間的區別時,我們將第一種稱為純粹的函數式編程,后者稱為函數式編程。函數式編程我們的準則是,被稱為函數式的函數或方法都只能修改本地變量。另一種觀點支持引用透明的函數式編程,認為方法不應該有對外部可見的對象修改。 一、實現和維護系統 1.共享的可變數據 如果一個方法既不修改它內嵌類的狀態,也不修改其他對象的狀態,使用return返回所有的計算結果,那么我們稱其為純粹...
摘要:其他語言數據結構跟算法一樣是在開始寫代碼的時候用得很少,都有著包裝好的現成東西供你使用,但同樣是面試和崗位上升會用得到,我就不說數據結構對代碼有多少好處,請記住一句話能夠實現個功能和能夠最優地實現個功能,是完全不同級別的要求。 ...
閱讀 1225·2021-11-11 16:54
閱讀 878·2021-10-19 11:44
閱讀 1337·2021-09-22 15:18
閱讀 2445·2019-08-29 16:26
閱讀 2946·2019-08-29 13:57
閱讀 3094·2019-08-26 13:32
閱讀 1081·2019-08-26 11:58
閱讀 2328·2019-08-26 10:37