再來(lái)聊聊繼承,以及超類 Object。
讓客戶滿意是我們工作的目標(biāo),不斷超越客戶的期望值來(lái)自于我們對(duì)這個(gè)行業(yè)的熱愛(ài)。我們立志把好的技術(shù)通過(guò)有效、簡(jiǎn)單的方式提供給客戶,將通過(guò)不懈努力成為客戶在信息化領(lǐng)域值得信任、有價(jià)值的長(zhǎng)期合作伙伴,公司提供的服務(wù)項(xiàng)目有:域名注冊(cè)、雅安服務(wù)器托管、營(yíng)銷軟件、網(wǎng)站建設(shè)、龍口網(wǎng)站維護(hù)、網(wǎng)站推廣。利用繼承,我們可以基于已存在的類構(gòu)造一個(gè)新類。繼承的好處在于,子類可以復(fù)用父類的非private
的方法和非private
成員變量。
is-a
是繼承的一個(gè)明顯特征,就是說(shuō)子類的對(duì)象引用類型可以是一個(gè)父類。我們可以將通用的方法和成員變量放在父類中,達(dá)到代碼復(fù)用的目的;然后將特殊的方法和成員變量放在子類中,除此之外,子類還可以覆蓋父類的方法。這樣,子類也就煥發(fā)出了新的生命力。
一個(gè)對(duì)象變量可以引用多種類型的現(xiàn)象被稱為多態(tài)。多態(tài)發(fā)生的前提條件就是繼承。也就是說(shuō),先有繼承,后有多態(tài)。
class Wanger {
public void write() {
System.out.println("我為自己活著");
}
}
class Wangxiaoer extends Wanger {
public void write() {
System.out.println("我也為自己活著");
}
}
class Test {
public static void main(String [] args) {
Wanger wanger;
wanger = new Wanger();
wanger = new Wangxiaoer();
Wangxiaoer wangxiaoer;
//wangxiaoer = new Wanger(); // 不可以
wangxiaoer = new Wangxiaoer(); // 只能這樣
}
}
wanger
這個(gè)對(duì)象變量既可以引用Wanger
對(duì)象,也可以引用Wangxiaoer
對(duì)象。但wangxiaoer
就只能引用Wangxiaoer
對(duì)象,不能引用Wanger
對(duì)象。根本的原因在于Wangxiaoer
是Wanger
的繼承者。
當(dāng)使用wanger
調(diào)用write()
方法時(shí),程序會(huì)在運(yùn)行時(shí)自動(dòng)識(shí)別其引用的對(duì)象類型,然后選擇調(diào)用哪個(gè)方法——這種現(xiàn)象稱為動(dòng)態(tài)綁定。
動(dòng)態(tài)綁定有一個(gè)非常重要的特性:無(wú)需對(duì)現(xiàn)有的代碼進(jìn)行修改,就能對(duì)程序進(jìn)行擴(kuò)展。假如Wangdaer
也繼承了Wanger
,并且wanger
引用了Wangdaer
的對(duì)象,那么wanger.write()
仍然可以正常運(yùn)行。
當(dāng)然了,有些類不愿意被繼承,也沒(méi)法被繼承。誰(shuí)不愿意被繼承呢?比如武則天,親手弄死自己的親兒子。誰(shuí)沒(méi)法被繼承呢,每朝每代最后的那位倒霉皇帝。
類怎么做到不被繼承呢?可以使用final
關(guān)鍵字。final
關(guān)鍵字修飾的類不能被繼承,final
修飾的方法不能被覆蓋。
final class Wanger {
public final void write() {
System.out.println("你們誰(shuí)都別想繼承我");
}
}
繼承是面向?qū)ο缶幊坍?dāng)中舉足輕重的一個(gè)概念,與多態(tài)、封裝共為面向?qū)ο蟮娜齻€(gè)基本特征。 繼承可以使得子類具有父類的成員變量和方法,還可以重新定義、追加成員變量和方法等。
在設(shè)計(jì)繼承的時(shí)候,可以將通用的方法和成員變量放在父類中。但不建議隨心所欲地將成員變量以protected
的形式放在父類當(dāng)中;盡管允許這樣做,并且子類可以在需要的時(shí)候直接訪問(wèn),但這樣做會(huì)破壞類的封裝性(封裝要求成員變量以private
的形式出現(xiàn),并且提供對(duì)應(yīng)getter / setter
用來(lái)訪問(wèn))。
Java 是不允許多繼承的,為什么呢?
如果有兩個(gè)類共同繼承一個(gè)有特定方法的父類,那么該方法會(huì)被兩個(gè)子類重寫。然后,如果你決定同時(shí)繼承這兩個(gè)子類,那么在你調(diào)用該重寫方法時(shí),編譯器不能識(shí)別你要調(diào)用哪個(gè)子類的方法。
這也正是著名的菱形問(wèn)題,見(jiàn)下圖。ClassC 同時(shí)繼承了 ClassA 和 ClassB,ClassC 的對(duì)象在調(diào)用 ClassA 和 ClassB 中重載的方法時(shí),就不知道該調(diào)用 ClassA 的方法,還是 ClassB 的方法。
在 Java 中,所有類都由 Object 類繼承而來(lái)。Object 這個(gè)單詞的英文意思是對(duì)象,是不是突然感覺(jué)頓悟了——萬(wàn)物皆對(duì)象?沒(méi)錯(cuò),Java 的設(shè)計(jì)者真是良苦用心了啊!現(xiàn)在,你一定明白了為什么 Java 是面向?qū)ο缶幊陶Z(yǔ)言的原因。
你可能會(huì)疑惑地反問(wèn)道:“我的類明明沒(méi)有繼承 Object 類?。俊比绻粋€(gè)類沒(méi)用顯式地繼承某一個(gè)類,那么它就會(huì)隱式地繼承 Object 類。換句話說(shuō),不管是雞生了蛋,還是蛋孵出了雞,總有一只 Object 雞或者一個(gè) Object 蛋。
在面試的時(shí)候,你可能會(huì)被問(wèn)到這么一個(gè)問(wèn)題:“Object 類包含了哪些方法呢?”
1)protected Object clone() throws CloneNotSupportedException
創(chuàng)建并返回此對(duì)象的副本。
不過(guò),《阿里巴巴 Java 開(kāi)發(fā)手冊(cè)》上建議:慎用 Object 的 clone 方法來(lái)拷貝對(duì)象。因?yàn)?Object 的 clone 方法默認(rèn)是淺拷貝,如果想實(shí)現(xiàn)深拷貝需要重寫 clone 方法實(shí)現(xiàn)屬性對(duì)象的拷貝。
什么是淺拷貝,什么是深拷貝呢?
淺拷貝是指在拷貝對(duì)象時(shí),會(huì)對(duì)基本數(shù)據(jù)類型的變量重新復(fù)制一份,而對(duì)于引用類型的變量只拷貝了引用,并沒(méi)有對(duì)引用指向的對(duì)象進(jìn)行拷貝。
深拷貝是指在拷貝對(duì)象時(shí),同時(shí)對(duì)引用指向的對(duì)象進(jìn)行拷貝。
淺拷貝和深拷貝的區(qū)別就在于是否拷貝了對(duì)象中的引用變量所指向的對(duì)象。
2)public boolean equals(Object obj)
判斷另一對(duì)象與此對(duì)象是否「相等」。
該方法使用的區(qū)分度最高的“==”操作符進(jìn)行判斷,所以只要兩個(gè)對(duì)象不是同一個(gè)對(duì)象,那么equals()
方法一定返回false
。
《阿里巴巴 Java 開(kāi)發(fā)手冊(cè)》上強(qiáng)調(diào):由于 Object 的 equals 方法容易拋出空指針異常,所以應(yīng)該使用常量或者確定不為 null 的對(duì)象來(lái)調(diào)用 equals。
正例:"test".equals(object);
反例:object.equals("test");
在正式的開(kāi)發(fā)項(xiàng)目當(dāng)中,最經(jīng)常使用該方法進(jìn)行判斷的就是字符串。不過(guò),建議使用org.apache.commons.lang3.StringUtils
,不用擔(dān)心出現(xiàn)空指針異常。具體使用情況如下所示:
StringUtils.equals(null, null) = true
StringUtils.equals(null, "abc") = false
StringUtils.equals("abc", null) = false
StringUtils.equals("abc", "abc") = true
StringUtils.equals("abc", "ABC") = false
3)public native int hashCode()
返回此對(duì)象的哈希碼。hashCode()
是一個(gè)native
方法,而且返回值類型是整行;實(shí)際上,該方法將對(duì)象在內(nèi)存中的地址作為哈希碼返回,可以保證不同對(duì)象的返回值不同。
A native method is a Java method whose implementation is provided by non-java code.
native
方法是一個(gè)Java
調(diào)用非Java
代碼的接口。該方法的實(shí)現(xiàn)由非Java
語(yǔ)言實(shí)現(xiàn),比如 C。這個(gè)特征并非Java
所特有,其它的編程語(yǔ)言也有這個(gè)機(jī)制,比如C++
。
hashCode()
通常在哈希表中起作用,比如HashMap
。
向哈希表中添加Object
時(shí),首先調(diào)用hashCode()
方法計(jì)算Object
的哈希碼,通過(guò)哈希碼可以直接定位Object
在哈希表中的位置。如果該位置沒(méi)有對(duì)象,可以直接將Object
插入該位置;如果該位置有對(duì)象,則調(diào)用equals()
方法比較這個(gè)對(duì)象與Object
是否相等,如果相等,則不需要保存Object
;如果不相等,則將該Object
加入到哈希表中。
4)protected void finalize() throws Throwable
當(dāng)垃圾回收機(jī)制確定該對(duì)象不再被調(diào)用時(shí),垃圾回收器會(huì)調(diào)用此方法。不過(guò),fnalize
機(jī)制現(xiàn)在已經(jīng)不被推薦使用,并且在 JDK 9 開(kāi)始被標(biāo)記為deprecated
(過(guò)時(shí)的)。
5)public final Class getClass()
返回此對(duì)象的運(yùn)行時(shí)類。
當(dāng)我們想知道一個(gè)類本身的一些信息(比如說(shuō)類名),該怎么辦呢?這時(shí)候就需要用到Class
類,該類包含了與類有關(guān)的信息。請(qǐng)看以下代碼:
Wanger wanger = new Wanger();
Class c1 = wanger.getClass();
System.out.println(c1.getName());
// 輸出 Wanger
6)public String toString()
返回此對(duì)象的字符串表示形式。
《阿里巴巴 Java 開(kāi)發(fā)手冊(cè)》強(qiáng)制規(guī)定:POJO 類必須重寫toString
方法;可以使用 Eclipse 直接生成,點(diǎn)擊 「Source」→「Generate toString」。示例如下:
class Wanger {
private Integer age;
@Override
public String toString() {
return "Wanger [age=" + age + "]";
}
}
重寫toString()
有什么好處呢?當(dāng)方法在執(zhí)行過(guò)程中拋出異常時(shí),可以直接調(diào)用 POJO 的toString()
方法打印其屬性值,便于排查問(wèn)題。
POJO(Plain Ordinary Java Object)指簡(jiǎn)單的 Java 對(duì)象,也就是普通的
JavaBeans
,包含一些成員變量及其getter / setter
,沒(méi)有業(yè)務(wù)邏輯。有時(shí)叫做 VO (value - object),有時(shí)叫做 DAO (Data Transform Object)。
本篇,我們先談了面向?qū)ο蟮闹匾卣骼^承;然后談到了繼承的終極父類Object
。這些知識(shí)點(diǎn)都相當(dāng)?shù)闹匾?qǐng)務(wù)必深入理解!
上一篇:請(qǐng)用面向?qū)ο蟮乃枷?,談一談這次面試的過(guò)程
下一篇:Java:接口和抽象類,傻傻分不清楚?
謝謝大家的閱讀,原創(chuàng)不易,喜歡就隨手點(diǎn)個(gè)贊
創(chuàng)新互聯(lián)www.cdcxhl.cn,專業(yè)提供香港、美國(guó)云服務(wù)器,動(dòng)態(tài)BGP最優(yōu)骨干路由自動(dòng)選擇,持續(xù)穩(wěn)定高效的網(wǎng)絡(luò)助力業(yè)務(wù)部署。公司持有工信部辦法的idc、isp許可證, 機(jī)房獨(dú)有T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確進(jìn)行流量調(diào)度,確保服務(wù)器高可用性。佳節(jié)活動(dòng)現(xiàn)已開(kāi)啟,新人活動(dòng)云服務(wù)器買多久送多久。