來源:http://justin-x.cn/
對於剛接觸JAVA或者其他面向對象編程語言的朋友們來說,可能一開始都很難理解面向對象的概念以及類
和對象
的關係。筆者曾經帶過一個短期培訓班教授java入門基礎,在最後結束課程的時候,還有很多同學不太理解面向對象
的思維以及類
與對象
的意義。這幾天有空,就想着整理整理自己的思路,談談自己對面向對象以及類與對象的理解。
面向對象
首先,一言不和先百度,得到如下定義:
一切事物皆對象,通過面向對象的方式,將現實世界的事物抽象成對象,現實世界中的關係抽象成類、繼承,幫助人們實現對現實世界的抽象與數字建模。
我們知道,編寫程序的目的是爲了解決現實生活中的問題,編程的思維方式也應該貼近現實生活的思維方式。面向對象的編程方式就是爲了實現上述目的二出現的。它使得編程工作更直觀,更易理解。需要注意的是這裏說的編程不光是coding還包括了設計的過程也是面向對象的。
爲什麼說面向對象更貼近實際生活
想象一下,當我們向別人描述一樣事物時,我們都是怎麼說的?”它有像鴨子一樣的嘴巴”,”它有4條退”,”爪子裏還有蹼”,”它是哺乳動物但卻是卵生”。
這種HAS A
和 IS A
的表達方式往往可以簡單而高效的描述一樣事物。HAS A
描述事物的屬性或行爲,IS A
則說明了事物的類屬。
當我們把這一系列的屬性組合
起來便得到的鴨嘴獸這一類
,同時哺乳動物
一詞簡單精煉的表面了所有哺乳動物的特性而不用一一列出,這是繼承
特性的體現,同時卵生
又是多態
的體現。
這就是面向對象的思維特點,抽取(抽象
)有用的屬性和行爲(拋棄哪些無需關係的)組織(封裝
)成一個類。這個過程中你也許會發現很多屬性或方法是和另一個類相同的,那麼你就可以採用繼承
的方式避免重複(當然這個過程也有可能是,當你設計完一個個類後,才發現他們有共同點,然後再抽取出基類)。更重要的是,繼承是可以不原樣照搬的,我們可以通過重載
實現相同行爲或屬性的特有實現方式,這種特點稱之爲多態
,例如同樣的生產行爲,實現方式由胎生變爲卵生。請大聲念出,並牢牢記住面向對象的四個特徵:
- 抽象
- 封裝
- 繼承
- 多態
與早期結構化編程相比
早期結構化編程是面向過程的(功能),換句話說程序是由功能的集合組成,而調用者是作爲功能的參數傳入的。而在面向對象的程序中,對象是主體,程序是由對象的集合組成。一個對象中包含一系列符合設計的功能供其他對象調用。這麼說可能還是比較抽象~
例如:當我們設計一個五子棋遊戲時
面向過程的設計思路就是首先分析問題的步驟:
1、開始遊戲,2、黑子先走,3、繪製畫面,4、判斷輸贏,5、輪到白子,6、繪製畫面,7、判斷輸贏,8、返回步驟2,9、輸出最後結果。
把上面每個步驟用分別的函數來實現,問題就解決了。
而面向對象的設計則是從另外的思路來解決問題。
整個五子棋可以分爲:
1、黑白雙方,這兩方的行爲是一模一樣的,2、棋盤系統,負責繪製畫面,3、規則系統,負責判定諸如犯規、輸贏等。
第一類對象(玩家對象)負責接受用戶輸入,並告知第二類對象(棋盤對象)棋子佈局的變化,棋盤對象接收到了棋子的變化就要負責在屏幕上面顯示出這種變化,同時利用第三類對象(規則系統)來對棋局進行判定。(以上例子來自國內著名問答社區)
隨便寫點代碼,大家看看就好,不要太認真…
/** 玩家類 **/ public class Player { String name; //棋手名稱 boolean isFirst; //是否先手 int color_flag; //代表顏色 0-白 1-黑 Table table;//棋盤對象 public Player(String name,boolean isFirst;int color_flag){ this.name=name; this.isFirst=isFirst; this.color_flag=color_flag; } /** 下棋,x,y爲落子座標 **/ public void play(int x,int y) throws Exception{ if(this.table==null){ throw new IllegalArgumentException("玩家還未註冊到棋盤!"); } table.setNewPieces(x,y); } public void setTable(Table table){ this.table=table; } } /** 棋盤類 **/ public class Table{ List<Player> playerList=new ArrayList<Player>(); Referee referee ; public Table(){ referee =new Referee(this); } /** 註冊玩家 **/ public void registPlayer(Player player) throws Exception { //檢測棋盤中的玩家是否已滿,先手玩家和玩家選色是否衝突。 ....... playerList.add(player); player.setTable(this); } /** 落子 **/ public void setNewPieces(int x , int y){ //重新繪製棋盤 ...... //調用裁判對象,判斷結果 if(referee.isEnd){ End(); } } public void End(){ ....... } } /** 裁判類 **/ public class Referee(){ Table table; public Referee(Table table){ this.table=table; } public boolen isEnd(){ //判斷輸贏 .... return false; } }
然而事實上,通過上述示例代碼,我們不難發現,即使我們使用面向對象的方式,上面例子裏面向過程中提到的幾個下棋過程我們還是都實現了的,只不過程被封裝
到了類的方法中。所以說其實面向對象和麪向過程並不是編程的區別(需要實現的業務邏輯的量不會產生變化),而是設計的區別!
類與對象
類是抽象的,而對象是具體的
如何理解上面的話呢? 例如鴨嘴獸是類型,具體的鴨嘴獸A、鴨嘴獸B就是對象了。在JAVA中對象是通過new
關鍵字聲明的。 再例如,《紅色警戒》中美國大兵是一類
兵種,點擊製造後從兵營裏出來的那個會開槍的傢伙就是對象
了:
類
的定義就是一個模板,它描述的一類對象的屬性與行爲。類往往是抽象的、沒有實體的。哺乳動物是類
的概念,是抽象的,現實中沒有哺乳動物這一實體,只有具體的如老虎,獅子等。編程工作中套用這一思維模式,我們將程序中的實例抽象爲類,例如一個系統中的用戶有張三、李四我們會把他們抽象爲Person類,或者稱之爲一個名爲Person的數據類型。
對象
則是根據所屬類
模板創造出來的實實在在的事物。在程序中我將這個實實在在的事物稱之爲實例,我們爲它的屬性賦上特定的值,讓它成爲張三或者李四。在內存裏來說,對象是表示的就是具體數據。
前面說的都是概念性的東西,下面我們說說實際的運用過程中的理解。
從數據類型來說
以java爲例,數據類型分爲基本數據類型
和引用數據類型
。
基本數據類型就是byte,short,int,long,double,char,boolean
;其它的,需要用到new
關鍵字來賦值的都是引用數據類型。 類與對象指的便是引用數據的類型與其值(這裏指的類不光是class
,還包括接口、數組、枚舉、註解
)。 而引用指的是內存地址的引用,關於這點在後面說的內存時會細說。
看下面的代碼:
int a =1; Person b=new Person();
a 和 b 都是本身無意義的變量名。需要關注的是:a的類型是基本數據類型int值爲1,而b的類型是Person屬於引用類型,其引用的是new Person()這個對象。我們往往會說對象xx,比如這裏的對象b。但實際上b只是對象的引用,真正的對象是後面的new Person()!
需要注意的是String也是引用數據類型,只不過因爲使用率非常高,所以對於String,jvm支持其可 以像基本數據類型一樣使用:String a = “abc”; 同等於 String a = new String(“abc”);
總之呢,簡單來說類
指的的引用數據的類型,對象
是具體賦的值。爲了更深入理解,我們下面需要解釋下這個引用
是如何體現的。
什麼是引用(從內存來說)
要深入理解什麼是類,什麼是對象,什麼又是引用,就離不開說說java的內存使用方式。
在java中內存被大致劃分爲棧(stack)
與堆(heap)
(之所以是大致,是因爲還包括其它幾部分就不在這細說)。
關於什麼是棧與堆在這就不細說,有空我再整理一篇文章詳細說明。
在這裏我們只說一點:java中,基本數據類型以及對象的引用都保存在棧(stack)
,而對象則保存在堆(heap)
中,例如當如下代碼:
int a=1; Person p;
內存中的狀態大致如下:
int a = 1 是直接在棧中開闢空間,而對於未進行實例化的Person p因爲沒有有效的內存地址引用它的值是null。而當代碼進行如下修改時:
int a =1 ; Person p = new Person();
內存中的狀態大致如下:
Person p=new Person();
使得p的值=0x8da23也就是對象new Person();
在堆
中的地址。所以,到這裏後就不難理解之前說的對象的引用了,所謂引用其實就是堆內存地址的引用。
總結
隨着計算機技術的不斷提高,現在計算機不單單是用來解決運算問題,而是被用於解決越來越貼近現實生活的複雜問題。面向對象就是這一發展進程的產物,它使得編程工作更貼近人的思維方式,從而大大提升編程效率。
我們必須明白的是面向對象並不是一種編程方式,而是一種編程思維方式,這種思維方式涵蓋了分析,設計,編碼等。在面向對象編程中,程序的基本單元是對象
,數據封裝在對象中。類
是對象模板,是預定義好的結構,所謂的實例化一個類,所指的就是將數據填入模板。
最後,本人文筆不是很好,有待提高。寫文章和博客的最大目的是梳理自己的思路,其二是分享自己的想法,望大家多多吐槽,願共同提高。
PS:如果覺得我的分享不錯,歡迎大家隨手點贊、轉發。