重新認(rèn)識(shí)類(lèi)吧...
4.1 類(lèi)
類(lèi)(class)是構(gòu)造對(duì)象的模板或藍(lán)圖蝌衔。由類(lèi)構(gòu)造對(duì)象的過(guò)程稱(chēng)為創(chuàng)建類(lèi)的實(shí)例齿梁。
重要概念:
- 封裝:將數(shù)據(jù)和行為組合在一個(gè)包中痹扇,并對(duì)對(duì)象的使用者隱藏了數(shù)據(jù)的實(shí)現(xiàn)方式橡羞。實(shí)現(xiàn)封裝的關(guān)鍵在于絕對(duì)不能讓類(lèi)中的方法直接第訪問(wèn)其他類(lèi)的實(shí)例域。
- 繼承:可以通過(guò)拓展一個(gè)類(lèi)來(lái)建立另外一個(gè)新的類(lèi)拜效。
類(lèi)之間的關(guān)系
在類(lèi)之間喷众,最常見(jiàn)的關(guān)系有
- 依賴(lài)(“use-a”)
- 聚合(“has-a”)
- 繼承(“is-a”)
依賴(lài),如果一個(gè)類(lèi)的方法操縱另一個(gè)類(lèi)的對(duì)象紧憾,我們就說(shuō)一個(gè)依賴(lài)于另一個(gè)類(lèi)到千。
聚合,類(lèi)A的對(duì)象包含類(lèi)B的對(duì)象稻励。
繼承父阻,一種用于表示特殊與一般關(guān)系的。
關(guān)聯(lián)和聚合是一個(gè)意思望抽,只是UML符號(hào)表示不同加矛。聚類(lèi)的符號(hào)更易區(qū)分一點(diǎn)。
4.4 各種修飾符
實(shí)例域的修飾符
修飾符 | 作用 |
---|---|
public | 如果一個(gè)實(shí)例域被public修飾煤篙,那它可以被所有類(lèi)獲得斟览、修改,應(yīng)該避免用public修飾辑奈。 |
private | 可以被本類(lèi)的訪問(wèn)器獲取苛茂、修改器修改已烤。 |
final | 只能在初始化時(shí)設(shè)置值,在后面的操作中不能對(duì)它進(jìn)行修改妓羊。 |
static | 所有本類(lèi)的實(shí)例共享被static修飾的實(shí)例域胯究。即使沒(méi)有一個(gè)實(shí)例對(duì)象,靜態(tài)域也存在躁绸。它屬于類(lèi)裕循,而不屬于任何獨(dú)立的對(duì)象。 |
方法的修飾符
修飾符 | 作用 |
---|---|
public | 任何類(lèi)的任何方法都可以調(diào)用這些方法净刮。 |
private | 不會(huì)被外部其他類(lèi)調(diào)用剥哑,可以刪除它(意味著沒(méi)有類(lèi)依賴(lài)于該方法)。 |
static | 可以認(rèn)為staic方法是沒(méi)有this參數(shù)的方法淹父。靜態(tài)方法不能訪問(wèn)實(shí)例域株婴,因?yàn)樗荒懿僮鲗?duì)象。但是靜態(tài)方法啊可以訪問(wèn)自身類(lèi)中的靜態(tài)域暑认。靜態(tài)方法屬于類(lèi)而不屬于實(shí)例困介,建議使用類(lèi)名調(diào)用靜態(tài)方法。 |
在下面兩種情況下使用靜態(tài)方法:
- 一個(gè)方法不需要訪問(wèn)對(duì)象狀態(tài)穷吮,其所需參數(shù)都是通過(guò)顯示參數(shù)提供逻翁。
- 一個(gè)方法只需要訪問(wèn)類(lèi)的靜態(tài)域。
main方法也是靜態(tài)方法捡鱼,每個(gè)類(lèi)可以有一個(gè)main方法。這是一個(gè)常用于對(duì)類(lèi)進(jìn)行單元測(cè)試的技巧酷愧。
4.6 對(duì)象構(gòu)造
重載
如果多個(gè)方法有相同的名字驾诈、不同的參數(shù),便產(chǎn)生了重載溶浴。編譯器必須挑選出具體執(zhí)行哪個(gè)方法乍迄,它通過(guò)用各個(gè)方法給出的參數(shù)類(lèi)型與特定方法調(diào)用所使用的值類(lèi)型進(jìn)行匹配來(lái)挑選出相應(yīng)的方法。如果編譯器找不到匹配的參數(shù)士败,就會(huì)產(chǎn)生編譯時(shí)錯(cuò)誤闯两。
默認(rèn)域初始化
如果在構(gòu)造器中沒(méi)有顯示地給域賦予初值,那么就會(huì)被自動(dòng)地賦為默認(rèn)值:數(shù)值為0谅将、布爾值為false漾狼、對(duì)象引用為null。然而饥臂,只有缺少程序設(shè)計(jì)經(jīng)驗(yàn)的人才會(huì)這樣做逊躁。注意:局部變量必須明確地初始化。
無(wú)參數(shù)的構(gòu)造器
如果類(lèi)中提供了至少一個(gè)構(gòu)造器隅熙,但是沒(méi)有提供無(wú)參數(shù)的構(gòu)造器稽煤,則在構(gòu)造對(duì)象時(shí)如果沒(méi)有提供參數(shù)就會(huì)被視為不合法核芽。僅當(dāng)類(lèi)沒(méi)有提供任何構(gòu)造器的時(shí)候,系統(tǒng)才會(huì)提供一個(gè)默認(rèn)的構(gòu)造器酵熙。
顯式域初始化
初始值不一定是常量值轧简。也可以調(diào)用方法對(duì)域進(jìn)行初始化。
參數(shù)名
不好的命名方式:只有閱讀代碼才能夠了解參數(shù)n和參數(shù)s的含義匾二。
public Employee(String n, double s)
{
name = n;
salary = s;
}
建議的命名方式:
public Employee(String aName, double aSalary)
{
name = aName;
salary = aSalary;
}
還有一種方式:參數(shù)變量用同樣的名字將實(shí)例域屏蔽起來(lái)吉懊。
public Employee(String name, double salary)
{
this.name = name;
this.salary = salary;
}
調(diào)用另一個(gè)構(gòu)造器
如果構(gòu)造器的第一個(gè)語(yǔ)句形如this,這個(gè)構(gòu)造器將調(diào)用同一個(gè)類(lèi)的另一個(gè)構(gòu)造器假勿。
public Employee(double s)
{
// calls Employee(String, double)
this("Employee #" + nextId, s)
nextId++;
}
4.7 包
Java允許使用包(package)將類(lèi)組織起來(lái)借嗽。借助于包可以方便地組織自己的代碼,并將自己的代碼與別人提供的代碼庫(kù)分開(kāi)管理转培。
所有標(biāo)準(zhǔn)的Java包都處于java和javax包層次中恶导。
使用包的主要原因是確保類(lèi)名的唯一性。事實(shí)上浸须,為了確保包名的絕對(duì)唯一惨寿,Sun公司建議將公司的因特網(wǎng)域名以逆序的形式作為包名,并且對(duì)于不同的項(xiàng)目使用不同的子包删窒。對(duì)于我自己裂垦,可以使用如org.shijiatongxue.corejava。
在C++中肌索,與包機(jī)制類(lèi)似的是命名空間(namespace)蕉拢。在Java中,package與import語(yǔ)句類(lèi)似于C++中的namespace和using指令诚亚。
靜態(tài)導(dǎo)入
import語(yǔ)句不僅可以導(dǎo)入類(lèi)晕换,還增加了導(dǎo)入靜態(tài)方法和靜態(tài)域的功能。
例如:
import static java.lang.System.*;
就可以使用System類(lèi)的靜態(tài)方法和靜態(tài)域站宗,而不必加類(lèi)名前綴:
out.println("Goodbye, World!");
exit(0);
另外闸准,還可以導(dǎo)入特定的方法或域:
import static java.lang.System.out;
包作用域
如果沒(méi)有指定public或private,這個(gè)部分(類(lèi)梢灭、方法或變量)可以被同一個(gè)包中的所有方法訪問(wèn)夷家。
對(duì)于變量來(lái)說(shuō),必須顯示地標(biāo)記為private敏释,不然的話(huà)默認(rèn)為包可見(jiàn)库快。顯然,這樣做會(huì)破壞封裝性颂暇。
4.9 文檔注釋
類(lèi)注釋
類(lèi)注釋必須放在import語(yǔ)句之后缺谴,類(lèi)定義之前。
/**
*A {@code Card} object represents a playing card...
*...
*...
*/
public class Card
{
...
}
方法注釋
/**
* Raises the salary of an emplyee.
* @param byPercent the percentage by which to raise the salary(e.g. 10 means 10%)
* @return the amount of the raise
*/
public double raiseSalary(double byPercent)
{
double raise = salary * byPercent / 100;
salary += raise;
return raise;
}
域注釋
只需要對(duì)公有域(通常指的是靜態(tài)常量)建立文檔。例如湿蛔,
/**
* The "Hearts" card suit
*/
public static final int HEART = 1;
4.10 類(lèi)設(shè)計(jì)技巧
- 一定要保證數(shù)據(jù)私有
- 一定要對(duì)數(shù)據(jù)初始化
Java不對(duì)局部變量初始化膀曾,但是會(huì)對(duì)對(duì)象的實(shí)例域進(jìn)行初始化。最好不要依賴(lài)于系統(tǒng)的默認(rèn)值阳啥。而是應(yīng)該顯式低初始化所有的數(shù)據(jù)添谊。具體的初始化方式可以是提供默認(rèn)值。也可以是在所有的構(gòu)造器中設(shè)置默認(rèn)值察迟。 - 不要在類(lèi)中使用過(guò)多的基本類(lèi)型
就是說(shuō)斩狱,用其他的類(lèi)替代多個(gè)相關(guān)的基本類(lèi)型的使用。這樣會(huì)使類(lèi)更加易于理解且易于修改扎瓶。 - 不是所有的域都需要獨(dú)立的域訪問(wèn)器和域更改器
- 將職責(zé)過(guò)多的類(lèi)進(jìn)行分解
- 類(lèi)名和方法名要能夠體現(xiàn)它們的職責(zé)
命名類(lèi)名的良好習(xí)慣是采用一個(gè)名詞(Order)所踊、前面有形容詞修飾的名詞(RushOrder)或動(dòng)名詞修飾名詞(BillingAddress)。對(duì)于方法來(lái)說(shuō)概荷,習(xí)慣是訪問(wèn)器方法用小寫(xiě)get開(kāi)頭秕岛,更改器方法用小寫(xiě)的set開(kāi)頭。 - 優(yōu)先使用不可變類(lèi)
更改對(duì)象的問(wèn)題在于误证,如果多個(gè)線程視圖同時(shí)更新一個(gè)對(duì)象继薛,就會(huì)發(fā)生并發(fā)更改。其結(jié)果是不可預(yù)料的愈捅。如果類(lèi)是不可變的遏考,就可以安全地在多個(gè)線程間共享其對(duì)象。
本章完蓝谨。