您好,登錄后才能下訂單哦!
再來聊聊繼承,以及超類 Object。
利用繼承,我們可以基于已存在的類構造一個新類。繼承的好處在于,子類可以復用父類的非 private
的方法和非 private
成員變量。
is-a
是繼承的一個明顯特征,就是說子類的對象引用類型可以是一個父類。我們可以將通用的方法和成員變量放在父類中,達到代碼復用的目的;然后將特殊的方法和成員變量放在子類中,除此之外,子類還可以覆蓋父類的方法。這樣,子類也就煥發出了新的生命力。
一個對象變量可以引用多種類型的現象被稱為多態。多態發生的前提條件就是繼承。也就是說,先有繼承,后有多態。
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
這個對象變量既可以引用 Wanger
對象,也可以引用 Wangxiaoer
對象。但 wangxiaoer
就只能引用 Wangxiaoer
對象,不能引用 Wanger
對象。根本的原因在于 Wangxiaoer
是 Wanger
的繼承者。
當使用 wanger
調用 write()
方法時,程序會在運行時自動識別其引用的對象類型,然后選擇調用哪個方法——這種現象稱為動態綁定。
動態綁定有一個非常重要的特性:無需對現有的代碼進行修改,就能對程序進行擴展。假如 Wangdaer
也繼承了 Wanger
,并且 wanger
引用了Wangdaer
的對象,那么 wanger.write()
仍然可以正常運行。
當然了,有些類不愿意被繼承,也沒法被繼承。誰不愿意被繼承呢?比如武則天,親手弄死自己的親兒子。誰沒法被繼承呢,每朝每代最后的那位倒霉皇帝。
類怎么做到不被繼承呢?可以使用 final
關鍵字。final
關鍵字修飾的類不能被繼承,final
修飾的方法不能被覆蓋。
final class Wanger {
public final void write() {
System.out.println("你們誰都別想繼承我");
}
}
繼承是面向對象編程當中舉足輕重的一個概念,與多態、封裝共為面向對象的三個基本特征。 繼承可以使得子類具有父類的成員變量和方法,還可以重新定義、追加成員變量和方法等。
在設計繼承的時候,可以將通用的方法和成員變量放在父類中。但不建議隨心所欲地將成員變量以 protected
的形式放在父類當中;盡管允許這樣做,并且子類可以在需要的時候直接訪問,但這樣做會破壞類的封裝性(封裝要求成員變量以 private
的形式出現,并且提供對應 getter / setter
用來訪問)。
Java 是不允許多繼承的,為什么呢?
如果有兩個類共同繼承一個有特定方法的父類,那么該方法會被兩個子類重寫。然后,如果你決定同時繼承這兩個子類,那么在你調用該重寫方法時,編譯器不能識別你要調用哪個子類的方法。
這也正是著名的菱形問題,見下圖。ClassC 同時繼承了 ClassA 和 ClassB,ClassC 的對象在調用 ClassA 和 ClassB 中重載的方法時,就不知道該調用 ClassA 的方法,還是 ClassB 的方法。
在 Java 中,所有類都由 Object 類繼承而來。Object 這個單詞的英文意思是對象,是不是突然感覺頓悟了——萬物皆對象?沒錯,Java 的設計者真是良苦用心了啊!現在,你一定明白了為什么 Java 是面向對象編程語言的原因。
你可能會疑惑地反問道:“我的類明明沒有繼承 Object 類啊?”如果一個類沒用顯式地繼承某一個類,那么它就會隱式地繼承 Object 類。換句話說,不管是雞生了蛋,還是蛋孵出了雞,總有一只 Object 雞或者一個 Object 蛋。
在面試的時候,你可能會被問到這么一個問題:“Object 類包含了哪些方法呢?”
1)protected Object clone() throws CloneNotSupportedException
創建并返回此對象的副本。
不過,《阿里巴巴 Java 開發手冊》上建議:慎用 Object 的 clone 方法來拷貝對象。因為 Object 的 clone 方法默認是淺拷貝,如果想實現深拷貝需要重寫 clone 方法實現屬性對象的拷貝。
什么是淺拷貝,什么是深拷貝呢?
淺拷貝是指在拷貝對象時,會對基本數據類型的變量重新復制一份,而對于引用類型的變量只拷貝了引用,并沒有對引用指向的對象進行拷貝。
深拷貝是指在拷貝對象時,同時對引用指向的對象進行拷貝。
淺拷貝和深拷貝的區別就在于是否拷貝了對象中的引用變量所指向的對象。
2)public boolean equals(Object obj)
判斷另一對象與此對象是否「相等」。
該方法使用的區分度最高的“==”操作符進行判斷,所以只要兩個對象不是同一個對象,那么 equals()
方法一定返回 false
。
《阿里巴巴 Java 開發手冊》上強調:由于 Object 的 equals 方法容易拋出空指針異常,所以應該使用常量或者確定不為 null 的對象來調用 equals。
正例:"test".equals(object);
反例:object.equals("test");
在正式的開發項目當中,最經常使用該方法進行判斷的就是字符串。不過,建議使用org.apache.commons.lang3.StringUtils
,不用擔心出現空指針異常。具體使用情況如下所示:
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()
返回此對象的哈希碼。hashCode()
是一個 native
方法,而且返回值類型是整行;實際上,該方法將對象在內存中的地址作為哈希碼返回,可以保證不同對象的返回值不同。
A native method is a Java method whose implementation is provided by non-java code.<br>
native
方法是一個Java
調用非Java
代碼的接口。該方法的實現由非Java
語言實現,比如 C。這個特征并非Java
所特有,其它的編程語言也有這個機制,比如C++
。
hashCode()
通常在哈希表中起作用,比如 HashMap
。
向哈希表中添加 Object
時,首先調用 hashCode()
方法計算 Object
的哈希碼,通過哈希碼可以直接定位 Object
在哈希表中的位置。如果該位置沒有對象,可以直接將 Object
插入該位置;如果該位置有對象,則調用 equals()
方法比較這個對象與 Object
是否相等,如果相等,則不需要保存 Object
;如果不相等,則將該 Object
加入到哈希表中。
4)protected void finalize() throws Throwable
當垃圾回收機制確定該對象不再被調用時,垃圾回收器會調用此方法。不過,fnalize
機制現在已經不被推薦使用,并且在 JDK 9 開始被標記為 deprecated
(過時的)。
5)public final Class getClass()
返回此對象的運行時類。
當我們想知道一個類本身的一些信息(比如說類名),該怎么辦呢?這時候就需要用到 Class
類,該類包含了與類有關的信息。請看以下代碼:
Wanger wanger = new Wanger();
Class c1 = wanger.getClass();
System.out.println(c1.getName());
// 輸出 Wanger
6)public String toString()
返回此對象的字符串表示形式。
《阿里巴巴 Java 開發手冊》強制規定:POJO 類必須重寫 toString
方法;可以使用 Eclipse 直接生成,點擊 「Source」→「Generate toString」。示例如下:
class Wanger {
private Integer age;
@Override
public String toString() {
return "Wanger [age=" + age + "]";
}
}
重寫 toString()
有什么好處呢?當方法在執行過程中拋出異常時,可以直接調用 POJO 的 toString()
方法打印其屬性值,便于排查問題。
POJO(Plain Ordinary Java Object)指簡單的 Java 對象,也就是普通的
JavaBeans
,包含一些成員變量及其getter / setter
,沒有業務邏輯。有時叫做 VO (value - object),有時叫做 DAO (Data Transform Object)。
本篇,我們先談了面向對象的重要特征繼承;然后談到了繼承的終極父類 Object
。這些知識點都相當的重要,請務必深入理解!
上一篇:請用面向對象的思想,談一談這次面試的過程
下一篇:Java:接口和抽象類,傻傻分不清楚?
謝謝大家的閱讀,原創不易,喜歡就隨手點個贊
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。