夜光序言:
人總會在某個時刻,明知道回不到過去,卻還是忍不住想,如果……如果
正文:
以道御術 / 以術識道
一、Java 面向對象
1. 面向對象都有哪些特性以及你對這些特性的理解
1)繼承:繼承是從已有類得到繼承信息創建新類的過程。
提供繼承信息的類被稱爲父類(超類、基類);得到繼承信息的類被稱爲子類(派生類)。
繼承讓變化中的軟件系統有了一定的延續性,同時繼承也是封裝程序中可變因素的重要手段。
2) 封裝:通常認爲封裝是把數據和操作數據的方法綁定起來,對數據的訪問只能通過已定義的接口。
面向對象的本質就是將現實世界描繪成一系列完全自治、封閉的對象。
我們在類中編寫的方法就是對實現細節的一種封裝;我們編寫一個類就是對數據和數據操作的封裝。
可以說,封裝就是隱藏一切可隱藏的東西,只向外界提供最簡單的編程接口。
3) 多態性:多態性是指允許不同子類型的對象對同一消息作出不同的響應。
簡單的說就是用同樣的對象引用調用同樣的方法但是做了不同的事情。
多態性分爲編譯時的多態性和運行時的多態性。
如果將對象的方法視爲對象向外界提供的服務,那麼運行時的多態性可以解釋爲:當 A 系統訪問 B 系統提供的服務時,B 系統有多種提供服務的方式,但一切對 A 系統來說都是透明的。
方法重載(overload)實現的是編譯時的多態性(也稱爲前綁定),而方法重寫(override)實現的是運行時的多態性(也稱爲後綁定)。
運行時的多態是面向對象最精髓的東西,要實現多態需要做兩件事:
1. 方法重寫(子類繼承父類並重寫父類中已有的或抽象的方法);
2. 對象造型(用父類型引用引用子類型對象,這樣同樣的引用調用同樣的方法就會根據子類對象的不同而表現出不同的行爲)。
4)抽象:抽象是將一類對象的共同特徵總結出來構造類的過程,包括數據抽象和行爲抽象兩方面。
抽象只關注對象有哪些屬性和行爲,並不關注這些行爲的細節是什麼。
注意:默認情況下面向對象有 3 大特性,封裝、繼承、多態,如果面試官問讓說出 4 大特性,那麼我們就把抽象加上去。
2. 訪問權限修飾符 public、private、protected, 以及不寫(默認)時的區別
3. 如何理解 clone 對象
3.1 爲什麼要用 clone?
在實際編程過程中,我們常常要遇到這種情況:有一個對象 A,在某一時刻 A 中已經包含了一些有效值,此時可能會需要一個和 A 完全相同新對象 B,並且此後對 B 任何改動都不會影響到 A 中的值,也就是說,A 與 B 是兩個獨立的對象,但 B 的初始值是由 A 對象確定的。
在 Java 語言中,用簡單的賦值語句是不能滿足這種需求的。
要滿足這種需求雖然有很多途徑,但實現 clone()方法是其中最簡單,也是最高效的手段。
3.2 new 一個對象的過程和 clone 一個對象的過程區別
new 操作符的本意是分配內存。
程序執行到 new 操作符時,首先去看 new 操作符後面的類型,因爲知道了類型,才能知道要分配多大的內存空間。
分配完內存之後,再調用構造函數,填充對象的各個域,這一步叫做對象的初始化,
構造方法返回後,一個對象創建完畢,可以把他的引用(地址)發佈到外部,在外部就可以使用這個引用操縱這個對象。
clone 在第一步是和 new 相似的,都是分配內存,調用 clone 方法時,分配的內存和原對象(即調用 clone 方法的對象)相同,然後再使用原對象中對應的各個域,填充新對象的域,填充完成之後,clone 方法返回,一個新的相同的對象被創建,同樣可以把這個新對象的引用發佈到外部。
3.3 clone 對象的使用
3.3.1 複製對象和複製引用的區別
1. Person p = new Person(23, "zhang");
2. Person p1 = p;
3. System.out.println(p);
4. System.out.println(p1);
當 Person p1 = p;執行之後, 是創建了一個新的對象嗎? 首先看打印結果:
1.com.hy.Person@2f9ee1ac
2.com.hy.Person@2f9ee1ac
可以看出,打印的地址值是相同的,既然地址都是相同的,那麼肯定是同一個對象。
p 和 p1 只是引用而已,他們都指向了一個相同的對象 Person(23, “zhang”) 。
可以把這種現象叫做引用的複製。上面代碼執行完成之後, 內存中的情景如下圖所示:
而下面的代碼是真真正正的克隆了一個對象。
1.Person p = new Person(23, "zhang");
2.Person p1 = (Person) p.clone();
3.System.out.println(p);
4.System.out.println(p1);
從打印結果可以看出,兩個對象的地址是不同的,也就是說創建了新的對象, 而不是把原對象的地址賦給了一個新的引用變量:
1. com.hy.Person@2f9ee1ac
2. com.hy.Person@67f1fba0
以上代碼執行完成後, 內存中的情景如下圖所示: