不知道是ESET的問題,還是開發商的問題,我在千千靜聽官網下載的播放器、百度下載的百度影音和優酷下載的iKu軟體,結果
都被ESET報潛在威脅,這軟體編寫的讓人蛋疼,不知道殺軟和應用軟體什麼時候才能正常。
前面幾天因為公司的事,忙的不行,也就沒有及時更新文字,今天小休班,因此來園子了逛逛, 繼續我的Java之旅,前面大體
描述了一些Java的基礎點,今天我們來討論Java中的OOP。
【OOP】
OOP? 什麼是OOP,說實話,我也不明白,我估計也沒有一個完整的非常嚴格的定義,OOP這個概念需要描述,不是簡單的定義
就能說明白的。
OOP:物件導向編程, 這裡強調的是“對象”這個概念, 那什麼是對象呢?如果您對Unix中,檔案的概念比較熟悉的話,應該瞭解
這麼一個事實:在UNIX中一切皆檔案。 在這裡,我們可以提升一個類似的概念: 在OOP的世界裡,一切皆對象。就是說任何一個東西
、任何一件事都可以抽象為一個對象,這裡有點辯證哲學的意味,有點方法論的調調;編程人員沒有必要死死的抓這個概念,編程人員需要
理解的事OOP的各種特徵: 封裝、繼承和多態。
【封裝】
封裝的目的就是為了躲貓貓,為了不讓你任意的訪問類中的執行個體域和方法。
封裝: 封裝是OOP的一個重要特點,有點像躲貓貓,也有點“金屋藏嬌”的意思,這個“嬌娃”也和時下炒作的沸沸揚揚的二奶一樣,會給
你找麻煩。封裝的目的就是不讓你瞭解內部的具體實現。
封裝從形式上看就是將:資料和操作行為耦合在一起,同時不向對象的使用者公開內部的具體實現和結構,而是提供給使用者一套介面,
使用者只要知道介面規範,就能正確無誤的使用對象。
封裝後對象的資料稱為執行個體域,而操作資料的過程(有時候可能是函數)稱為方法。
封裝的要點就是:不能讓對象的方法直接存取其他的類執行個體域。
【繼承】
繼承的目的是為了提高代碼的複用效能。
繼承這個概念或者說這個理論不知道和生物學有沒有關係,看了很多資料都沒有提及到這個問題,我一直很迷惑,因為大自然存在的很多
事情都是人類科技模仿的對象,也許這個也有關係。
繼承和基因的遺傳比較類似; 假令類A為父類(或者說是基類),類B為子類(或者說是擴充類),這樣類B就具有類A所有的特性,這個
就與基因的遺傳一樣了,兒子繼承了父親的基因;而通常我們在設計子類的時候,不會完全與父類相同,這個就與基因的變異相似了;而如果
類B還繼承了類C,這個就和兒子繼承了來自母親的基因類似了,但是很不幸的事,Java中不允許多重繼承(悲劇了,C++中允許多重繼承,Java
中的子類註定是個單親家庭的孩子);如果要實現多重繼承需要其他的機制,貌似介面機制可以實現。
【多態】
多態的目的是什麼呢?多態的目的是為了提高介面的適用度。
多態性怎麼說呢? 沒有比較合適的比喻, 不過倒有一個情境適合說明這個問題:C語言中求兩個數值最大值或者最小值的函數。
Exp:
int imax(int iValueA,int iValueB){ return iValueA>iValueB?iValueA:iValueB; }
這裡我們可以看到,由於類型的限制,我麼不能利用這個函數求實數的最大值,為了求實數的最大值我們必須寫一個功能類似的函數
並且我們還必須為實數的函數設計一個新的名字,問題就來了,我們在使用的過程中,希望是一個函數名,既可以用來求int類型的最值,
同時也可以用來求實數的最值,這樣使用者不必當心函數名是否正確,我們只需要使用一個統一調用格式即可。
這裡求最值的函數我們希望是這樣的: the_max_value=max(valueA,valueB); 這個調用格式既可以滿足int類型,也可以滿足
float類型,我們不必關心傳入的參數的資料類型。 這在C語言中,是不太現實的,而OOP則可以非常容易的實現這個要求。在C++中通過
函數重載很容易實現;這就是說我們可以這樣定義:
max(int ValueA,int ValueB); //method 1
max(double ValueA,double ValueB); //method 2
而我們調用的時候,採用: the_max_value=max(valueA,valueB); 即可,運行時會根據傳入的參數類型,自動選擇method 1 或者
method 2.
多態在Java中與C++的多態還有很多的不一樣,例如在C++中可以實現運算子的重載,而在Java中不能進行運算子多載(前面說過的字元
串聯接運算子 + 不是運算子多載的結果,雖然兩者看起來非常相似)。
【OOP小結】
上面討論的都是方法論範疇的東西,並沒有涉及到具體的實現,這個需要注意,思想決定思路。
【類和對象】
大家應該見過塑瓷菩薩,手藝匠師有一個塑料的模子,然後會有已經攪拌好的石膏粉,當要塑造瓷菩薩的時候,匠師
將模子將石膏粉弄成菩薩的模樣後,將模子取下來就是一個菩薩。
這裡類就是模子,對象就是塑成的菩薩,而石膏粉就是記憶體空間了。
【對象】
要使用一個東西,這個東西必須存在;否則就是鏡花水月了。
對象也一樣,要使用對象,必須先存著對象,那麼在Java中對象是如何來的呢?
在OOP中,要用構造器來構造對象;接觸過C++的人,應該知道,在C++中,構造器就是類的建構函式。而在Java中也一樣必須有
構造器來構造對象。
Java中構造器是類的一個公有的方法(public method);構造器必須與類名一致;構造器用來執行個體化一個對象,同時設定對象的初始狀態。
構造器方法可以有參數,也可以沒有參數。
在用構造器方法執行個體化對象的時候,需要向系統申請記憶體空間,這個申請空間的過程由new操作符來完成。例如在Java內建庫中有一個Date類,
如果我們需要構造一個Date對象,如下所示:
new Date();
這裡我們確實構造了一個Date對象,但是如果這樣的話,我們以後將沒有辦法使用這個Date對象
當然如果對象僅需要使用一次,那麼我們可以這樣做:
String dateStr=new Date().toString;
這裡我們使用了這個對象的方法toString。
如要我們需要在構造一個對象後,多次使用這個對象,那麼就需要定義一個物件變數。通過物件變數來引用構造出來的對象。如下
所示:
Date birthday; //定義了一個Date類的物件變數,這個物件變數分配了記憶體空間,但是這個記憶體空間不是Date對象需要的記憶體空間。
birthday=new Date(); //將birthday與新構造出來的Date對象關聯起來,同時new 操作符向系統申請了一塊空間來表示Date對象。
這裡我們需要分辨一下birthday物件變數和Date對象。他們的關係如所示:
這裡與C++中的引用有點類似,但是需要分辨引用與物件變數之間的區別。在C++中,沒有Null 參考,同時在C++中引用不能多次賦值;
就是說在C++中引用在設定好後,就不能被改變,而在Java中物件變數是可以改變指向的,這一點需要注意。
要點:
物件變數不是對象本身,並且只有當用對象初始化物件變數後才能使用物件變數。
Date birthday;String str=birthday.toString(); //編譯時間錯誤
這裡錯誤是因為物件變數只有被對象初始化後才能引用對象。初始化物件變數有兩種方法,如下所示。
Exp:
Date birthday=new Date();Date deadline;deadline=birthday;
birthday和deadline之間的關係如所示:
要點:
【Null 物件】
在Java中有一個預定義的對象null——Null 物件。
可以顯示的將一個物件變數設定為null, 設定為null的物件變數表示沒有引用任何對象。如果調用設定為null的物件變數的方法,就相當於引用一個Null 物件,
引用Null 物件的方法將產生一個運行時錯誤。
Exp:
Date birthday=null;System.out.println(birthday.toString()); //將產生一個執行階段錯誤
【對象的儲存空間】
這裡暫時不討論這個問題,等我們將OOP這個主題討論完後,我們再來討論一下對象空間分配的相關內容。
【更改器方法和訪問器方法】
我們知道類中的執行個體域儲存的對象的資訊,而方法是用來對執行個體域進行操作的;這裡我們一般將讀取執行個體域資訊的方法叫做訪問器方法;
而將修改執行個體域的方法叫做更改器方法。
設計更改器方法和訪問器方法的目的是支援對象(或者說類)的封裝特性。
要修改或者擷取一個類的執行個體域,通常建議用更改器方法或訪問器方法,這樣可以保證執行個體域訪問的有效性。
雖然我們可以定義public的執行個體域,但是不建議這麼做,為了封裝性,建議用更改器方法和訪問器方法。
【設計一個僱員類】
僱員類應該包括什麼資訊呢?
1、name
2、gender
3、phone number(telphone number)
4、salary
前面說了要執行個體化一個對象,必須有構造器,因此僱員類還必須至少有一個構造器方法。
1、employee();
為了擷取僱員的資訊和修改僱員的資訊,我們還必須有更改器方法和訪問器方法。
1、getName;
2、getGender
3、getPhoneNumber
4、getSalary
5、setName
6、setGender
7、setPhoneNumber
8、setSalay
我們擷取資訊後,有時需要列印出來查看,這就需列印相關的方法
1、printName
2、printGender
3、printPhoneNumber
4、printSalary
【代碼風格】
在設計類的時候,代碼的順序一般不影響程式的運行,但是在實際操作的時候,不同的人會有不同的風格,
例如有的人喜歡這樣設計:
class className
{
field1;
field2;
.....
construct method1;
construct method2;
.....
method1;
method2;
.......
}
而有的人則喜歡這樣設計:
class className
{
construct method1;
construct method2;
.....
field1;
field2;
.....
method1;
method2;
.....
}
還有的人喜歡這樣設計:
class className
{
construct method1;
construct method2;
.....
method1;
method2;
.....
field1;
field2;
.....
}
我個人認為,究竟使用哪種風格並不重要,重要的是要在代碼編輯的過程中,保持一致,這樣才不至於給後期的代碼維護和升級帶來
太多的麻煩。
不過我現在看的這本書的作者則喜歡第三種風格;作者是這樣的認為的:
使用這種風格會促使類的設計者在,在沒有編輯代碼的時候,首先設計好類,然後才決定編寫代碼,這樣不會在代碼編輯的過程中出現寫到
一半的時候突然想起需要增加一個執行個體域或者突然想起要增加一個方法的情況,這樣時間長了有利於提高程式人員的設計類的實踐能力。
【代碼】
下面是設計的代碼,因為時間的原因,沒有寫完了。
/*設計僱員類*/class employee{ public employee(String inName,boolean inGender,String inPhoneNumber,double inSalary) { if(!setName(inName)) { } setGender(inGender); setPhoneNumber(inPhoneNumber); setSalary(inSalary); } public String getName() { return Name; } public boolean getGender() { return Gender; } public String getPhoneNumber() { return PhoneNumber; } public double getSalary() { return Salary; } public boolean setName(String inName) { if(inName.equals("")) { System.out.println("you haven't enter you name"); retrun false; } Name=inName; } public boolean setGender(boolean inGender) { } public boolean setPhoneNumber(String inPhoneNumber) { } public boolean setSalary(double inSalary,boolean raise) { } public void printName() { } public void printGender() { } public void printPhoneNumber() { } public void printSalary() { } private String Name; private boolean Gender; private String PhoneNumber; private double Salary;}
呵呵,下次有時間將代碼不全,同時這個地方還有點內容需要在討論一下。