文章目錄
1. 類和對象
之前初學得時候寫的文章👉Java類和對象
簡單概括來說就是一句話:類是設計圖,對象是產品,一個是抽象的不存在的東西,一個是現實的能用的東西。
-
類是對一類事物的描述,是抽象的
-
對象是類事物的實例,是貝體的
-
類是對象的模板,對象是類的實體
那你要用這個類(設計圖),你就要先實例化對象(把這個設計圖上的東西造出來用)
就像樓盤,你得現有設計圖紙,才能造房子呀。對於住房的人來說,設計圖紙又用不了;但是沒有圖紙又沒法造房子。
所以,得出了結論:
類是對象的抽象,對象是類的實例
在Java中,一切皆對象,因爲類不能用呀。但是必須現有類纔能有對象,因爲對象的產生依賴於類的實例化。(設計圖紙也沒你談什麼造房子)
類的定義與使用
類的組成:
-
成員變量:對應事物的屬性
-
成員方法:對應事物的行爲
具體的使用參見👉Java類和對象
單個對象調用內存圖
程序的入口是main
方法,從mian
方法處開始執行
-
先實例化對象,在棧上存放對象的地址
-
在堆上創建新的對象(
new
出來的) -
實例化對象,爲成員變量賦值
-
在引用成員方法時,先通過棧上存放的引用地址找到堆內存上成員方法的地址(成員方法放在成員方法區Method Area)
-
根據堆上的引用找到方法區的method調用
-
方法區的方法要想執行,先壓入到棧中才能執行。在主方法中調用的順序就是執行的順序。壓入棧中執行完後立即彈出釋放
-
最後全部執行完成,主方法也銷燬(主方法是最先執行的方法,由棧的結構可知最後釋放)
兩個對象調用同一個方法內存圖
上面的例子是實例化了一個對象來調用方法,那一個類實例化兩個甚至是多個對象,怎麼來調用呢?
在Phone類中有三個方法,實例化了兩個對象one
和two
,new
了幾次,就在堆上開闢幾個新空間。但是方法不會創建兩次,兩個在堆上實例的對象引用的都是方法區同一個地址。
這裏還有一個概念,叫引用傳遞
引用傳遞:一塊堆內存可以被多個棧內存所指向
User user1 = new User();
User user2 = user1;
就是將user1在堆上實例化對象的地址引用賦給user2,此時兩個棧引用指向同一塊堆內存
一個有意思的問題就來了。在方法之間,即可以傳遞值,也可以進行引用傳遞。那麼,Java參數傳遞的方式,到底是值傳遞還是引用傳遞?
Java中到底是值傳遞還是引用傳遞
給出結論:Java參數傳遞方式的爲值傳遞,並且只有值傳遞一種
詳情參見:👇👇👇👇👇👇
成員變量與局部變量
局部變量與成員變量:
1. 定義的位置不一樣
-
局部變量:定義在方法中
-
成員變量:定義在類中
2. 作用範圍不一樣
-
局部變量:作用在定義的方法中
-
成員變量:作用在類中
3. 默認值不一樣
-
局部變量:無默認值,要想使用必須手動賦初值
-
成員變量:如果沒有賦值,會有默認值
-
如果是整數 默認爲0
-
如果是浮點數 默認爲0.0
-
如果是字符 默認爲’\u0000’
-
如果是布爾 默認爲 false
-
如果是引用類型 默認爲null
-
4. 內存位置不一樣
-
局部變量:棧中
-
成員變量:堆中
5. 生命週期不一樣
-
局部變量:進棧誕生,出棧消失
-
成員變量:對象創建產生,對象被回收消失
this關鍵字
this關鍵字主要有以下三個方面用途:
-
this調用本類屬性
-
this調用本類方法(構造方法和成員方法)
-
this表示當前對象
當方法的局部變量和類的成員變量重名的時候,根據“就近原則”,優先使用局部變量
如果需要訪問本類當中的成員變量,需要使用格式:this.成員變量名
super關鍵字
this關鍵字主要有以下三個方面用途:
-
在子類的成員方法中,訪問父類的成員變量。
-
在子類的成員方法中,訪問父類的成員方法。
-
在子類的構造方法中,訪問父類的構造方法。
super和this兩種構造調用,不能同時使用,因爲都得放在第一行,不能同時滿足。
2. 面向對象的思想
面向對象,面向是什麼?爲什麼面向的是對象?
面向誰,就更加關注誰。我們面向對象自然就是更加關注“對象”了。
俺沒有對象,不知道有“對象”的思想是什麼。有對象的鐵汁萌好好關心一下對象,沒有的也別
new
了。好好學習就完事了,等着國家分配吧。
那,爲什麼要面向對象呢?因爲我們關注的不再是程序具體怎麼實現的,而是更加關注實現了什麼功能。
面向對象的思想來源於生活,大神們設計編程語言都是基於“來源於生活但是高於生活”的思想來設計的。面向對象,就是我關注的是”用什麼來實現這件事“,面向過程更加關注“怎麼來實現”。一個強調結果,誰能幫我幹成;一個強調過程,我怎麼來做。
就像洗衣服,面向過程就是自己洗,先把衣服放盆裏用洗衣液浸泡,然後洗衣服,晾衣服。面向對象則是直接把衣服扔給我們的對象------“全自動洗衣機”來洗,我不關係它怎麼洗的,我只關心洗乾淨沒有.
其實,與面向過程相比,就是關注的點不一樣了,我們來二者對比一下,更好的說明。
面向對象,也有偷懶一說。其實就是別人封裝寫好的功能,你不用管怎麼實現的,你關心的是用別人寫好的東西來實現自己想要的功能。
其實,在這一點上,相比於Java,Python(動態的、面向對象的腳本語言)更具有代表性,Python有很多很多第三方的類庫,都是別人寫好的功能,使用更加方便。
我們拿一個打印數組來說明:
【面向過程】
【面向對象】
Arrays.toString()
方法源碼:
面向過程全部需要自己來實現手工打印,而面向對象則直接調用打印數組的方法。就好像別人都在用打火機了,你還在鑽木取貨。但是對比而言,面向過程擁有更高的執行效率,這是面向過程不具備的優勢。
3. 面向對象的三大特徵
面向對象名詞擴展
-
OOA:面向對象分析
-
OOD:面向對象設計
-
OOP:面向對象編程
面向對象三大特徵
-
封裝性:類內部操作對外部的不可見性(保護性)
-
繼承性:子類繼承了父類所有的功能,並在無需重新編寫原來的類的情況下對這些功能進行擴展
-
多態性:多態是同一個行爲具有多個不同表現形式的能力
4. 封裝
詳情參見:👇👇👇👇👇👇
5. 繼承
繼承是爲了更好地複用之前的代碼。子類繼承了父類所有的功能(不能選擇性的繼承,只能是全繼承),並在無需重新編寫原來的類的情況下對這些功能進行擴展。
Java中的繼承是單繼承,要想實現多繼承則可以使用接口或者多重繼承
-
類與類之間是單繼承的。直接父類只有一個
-
類與接囗之間是多實現的。一個類可以實現多個接口
-
接囗與接囗之間是多繼承的
繼承注意事項:
- 子類擁有父類對象所有的屬性和方法(包括私有屬性和私有方法),但是父類中的私有屬性和方法子類是無法訪問,只是擁有(因爲封裝對外的不可見性)。
- 子類可以擁有自己屬性和方法,即子類可以對父類進行擴展。
- 子類可以用自己的方式實現父類的方法。
繼承中成員變量訪問規則:
在父子類的繼承關係當中,創建子類對象,訪問成員變量的規則:
- 就近原則
繼承中成員方法訪問規則:
在父子類的繼承關係當中,創建子類對象,訪問成員方法的規則:
- 創建的對象是誰,就優先用誰(new 的誰,就用誰),如果沒有則向上找
繼承中構造方法訪問規則:
-
子類構造方法中有一個默認隱含的
super()
調用,所以一定先調用父類構造,再調用子類(先有父親纔有兒子) -
子類構造可以通過
super
關鍵字來調用父類重載構造,不寫則默認調用父類無參構造,寫了則調用指定參數 -
父類構造調用,必須是子類構造方法的第一個語句,而且只能調用一次
重載(overload)和重寫(override)
重載就是同樣的一個方法能夠根據輸入的數據的類型不同,做出不同的處理
重載就是同一個類中,多個同名方法根據不同的傳參來執行不同的邏輯處理。
重寫
重寫就是當子類繼承父類的相同方法,輸入數據一樣,但要實現和父類不同的功能時,就需要覆寫父類方法
重寫發生在運行期,是子類對父類的允許訪問的方法的實現過程進行重新編寫。
- 返回值類型、方法名、參數列表必須相同,拋出的異常範圍小於等於父類,訪問修飾符範圍大於等於父類。
- 如果父類方法訪問修飾符爲 private/final/static ,則子類就不能重寫該方法,但是被 static 修飾的方法能夠被再次聲明。
- 構造方法無法被重寫
重載就是產生一個新的,覆寫就是把原來的覆蓋了。
請解釋 方法重載(overload) 和 方法覆寫(override) 的區別:
子類方法重名問題
局部變量:直接寫成員變量名
本類的成員變量:this.成員變量名
父類的成員變量:super.成員變量名
6. 多態
多態性:多態是同一個行爲具有多個不同表現形式的能力
extends繼承或者implements實現,是多態性的前提
【多態性的理解】:對象又有多種表現的形態
就好比說張三這個學生,是屬於人類的。這種說法是正確的,因爲一個學生,本來就是一個人。我們先說的是小範圍的,再說大範圍的。
那要是反過來說,人類就是一個學生沒這肯定不行了。因爲他可能早就畢業了,現在不是學生了,而是一個員工了。
那麼,這也就剛好說明了,實現多態性的前提就是,發生在繼承關係的類中(接口的實現,也可以看做是繼承)。正因爲學生類繼承了人類,才能說“張三這個學生,是屬於人類的”;但是人類沒有繼承學生類呀,所以“人類就是一個學生”的說法是錯誤的。
多態性的體現
現在我有兩個類,一個是Fu
類,一個是Zi
類,Zi
類繼承了Fu
類。
多態性在代碼中的體現:父類引用指向子類對象
Fu odj = new Zi(); //父類引用指向子類對象
多態中成員變量的訪問:
訪問成員變量的兩種方式:
-
直接通過對象名稱訪問成員變量:看等號左邊是誰,優先用誰,沒有則向上找
-
間接通過成員方法訪問成員變量:看該方法屬於誰,優先用誰,沒有則向上找
輸出結果:
10
10
多態中成員方法的訪問:
-
看
new
的是誰,就優先用誰,沒有則向上找 -
編譯看左邊,運行看右邊
輸出結果:
方法執行👉子類
父類特有方法.
那我再訪問一下子類的methodZi()
呢?
- 會出現編譯報錯
編譯看左邊,左邊是Fu,Fu當中沒有methodeZi()
方法,所以編譯報錯
【多態在代碼中的體現總結:】
-
成員變量:編譯看左邊,運行還看左邊
-
成員方法:編譯看左邊,運行看右邊,
new
的誰,就執行誰
向上轉型
向上轉型:其實就是多態的寫法
【格式】:父類名稱 對象名 = new 子類名稱( );
【含義】:右側創建一個子類對象,把它當做父類來看待使用
Animal animal = new Cat();
【注意事項】:向上轉型一定是安全的。從小範圍轉向了大範囤,從小範圍的貓,向上轉換成爲更大範囤的動物。
可以類比爲自動類型的轉換
double num = 100; //int----->double
向下轉型
向下轉型:其實是一個【還原】的動作。
Q:還原的是誰呢?
- 在發生向下轉型之前,一定先發生向上轉型,還原的是向上轉型時子類的對象。
【格式】:子類名稱 對象名 =(子類名稱) 父類對象
【含義】:將父類對象,[ 還原 ] 成爲本來的子類對象
Animal animal = new Cat(); //本來是貓,向上轉型成爲動物
Cat cat =(cat) animal; //本來是貓,已經被當做動物了,還原回來成爲本來的貓
運行結果:
Exception in thread “main” java.lang.ClassCastException: 狗類轉換異常
😼貓吃魚
貓捉老鼠
【注意事項】
a. 在發生向下轉型的時候,必須先向下轉型。就是必須保證對象本來創建的時候,就是貓,才能向下轉型成爲貓。
b. 如果對象創建的時候本來不是貓,現在非要向下轉型成爲貓,就會報錯ClassCastException<類型轉換異常>
可以類比爲強制轉換
int num = (int) 10.0;
做個總結:
多態就是一個對象擁有多種表現的形態
這就是面向對象的一些知識要點了。其實,隨着學習的不斷地深入,面向對象的精華是思想在項目和框架中的應用。
【參考鏈接】