Java面向對象
一、類
- java程序的最基本單位
- 對一類有共同屬性和行爲事物的抽象叫做類
二、對象
1、定義
實實在在看得見摸得着的實體叫對象
- 注:new出來的對象存在於內存的
堆
中,有默認值。比如String
爲null
,int
爲0
代碼執行過程中內存原理分析
Demo
- 類的定義
package com.student;
public class Student {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void show(){
System.out.println("name=" + name + " , " +"age=" + age);
}
}
2、單對象內存原理
- 測試
package com.student;
public class StudentDemo {
public static void main(String[] args) {
Student s1 = new Student();
s1.setName("小明");
s1.setAge(18);
s1.show();
}
}
1、main
方法在內存中進棧
執行構造方法,創建一個Student類得實例對象s1,於是在內存的堆空間開闢空間存儲s1成員變量,並初始化成員變量。構造方法出棧。
2、setName
方法在內存中進棧
s1指向堆中的對象實例地址(假設是001),this指向的方法調用者實例,也就是s1.
方法執行結束出棧。
之後setAge
方法同理。
4、執行show
方法,show
方法在內存
3、多對象內存原理
- 測試
package com.student;
public class StudentDemo {
public static void main(String[] args) {
Student s1 = new Student();
Student s2 = new Student();
s1.setName("小明");
s2.setName("小紅");
s1.setAge(18);
s2.setAge(20);
s1.show();
s2.show();
}
}
後續方法調用同理,都是一個類方法執行,先進入內存棧區域,如果是賦值操作,那麼調用者對象便指向內存堆區域的真實地址,對成員變量進行賦值操作,在方法執行完畢之後,會將方法進行出棧,隨後後續方法接在內存中入棧,執行響應操作。
以demo的測試代碼爲例,接下來是Student的setAge方法入棧,調用者是s1,便指向s1在內存堆中的真實地址,對s1的age屬性進行賦值,之後setAge方法出棧,接着又是Student的setAge方法入棧,可這回調用者是s2,於是指向s2在內存堆中的真實地址,對s2的age屬性進行賦值,之後setAge方法出棧。接下來要執行的是Student類的show方法,兩個對象都有調用,依次是s1先調用show方法入棧,執行過後出棧,然後是s2調用show方法入棧,執行後出棧。最後main方法執行完畢,釋放s2,s1在內存中爲存儲成員變量開闢的空間,之後main方法出棧。到此爲止測試執行完畢。
4、對象指向相同地址的內存原理
- 測試
package com.student;
public class StudentDemo {
public static void main(String[] args) {
Student s1 = new Student();
s1.setName("小明");
s1.setAge(18);
Student s2 = s1;
s2.setName("小紅");
s2.setAge(20);
}
}
三、類中的變量
區別 | 成員變量 | 局部變量 |
---|---|---|
類中位置 | 類方法之外 | 類方法內或類方法聲明中 |
內存中位置 | 堆 | 棧 |
生命週期 | 因爲在堆中,所以隨着類得創建而創建,隨着類的銷燬而銷燬 | 因爲在棧中,所以隨着類方法的調用而產生,隨着方法的執行完畢而銷燬 |
初始化 | 有初始化 | 沒有初始化,必須要先創建,然後賦值,才能被使用 |
this指針
this修飾的變量指代成員變量
- 作用:解決局部變量隱藏成員變量的問題。
- 方法中this的指向:方法被哪個對象調用this就指向哪個對象。
private修飾符
屬於權限操作符,修飾類成員
- 作用:保護類成員不被其他類使用,被private修飾的變量只能本類使用!
四、構造方法
- 如果沒有定義構造方法,默認使用無參構造方法。
- 如果定義了構造方法,系統將不再提供構造方法(建議都手動加上無參構造方法)
五、面向對象三大特徵:封裝、繼承、多態
(一)封裝
封裝是面向對象編程語言對客觀世界的模擬,客觀世界裏的成員變量都是隱藏在對象內部,外界是無法直接操作的
- 原則:將類得某些信息通過private屬性隱藏在類內部,外界不能直接訪問,需要通過該類提供的public方法進行操作或訪問。
- 好處:
- 通過方法來控制成員變量的操作,提高了代碼的安全性。
- 把代碼用方法進行封裝,提高了代碼的複用性。
(二)繼承
繼承就是有一堆的類,把這些類的共性方法抽取出來,作爲一個父類(也可叫做超類、基類),之後這些類就作爲它的子類,這些子類就能繼承父類中的所有非私有成員。
- 注意事項:
- 子類繼承父類以後可以擁有父類的非私有成員
- 構造方法不能被繼承,私有成員不能被繼承,static修飾的成員不能被繼承
- 格式:class 子類 extends 父類
- 訪問成員變量:
- 不重名:如果訪問父類的對象,那隻能直接訪問父類的非私有成員變量。如果訪問子類的對象,那訪問的是子類和父類的非私有成員變量。
- 直接使用中,父類對象、本類對象重名:優先訪問
=
左邊的對象類型的變量,如果要對其進行區別可以使用this
來特指本類對象、super
特指父類對象 - 通過方法使用時,父類對象、本類對象、本類中的局部變量都重名:主要先看使用的是哪個類的方法,在方法中優先訪問本類的局部變量,訪問本類成員使用
this
指代,訪問父類的成員使用super
指代。
- 訪問成員方法
- 不重名:如果訪問的是父類的成員方法,那就只能訪問父類的成方法。如果訪問子類,那麼訪問的是子類的成員方法和父類的非私有成員方法。
- 重名:優先調用的同名方法主要看new的對象是什麼類型,如果要顯示進行區分最好使用
this
、super
來專門指代。
- 方法的重寫
-
要求:重寫的方法必須和原來的方法一模一樣,雖然可以在方法的返回值可以是原來方法的子類型,但一般還是寫作一模一樣的類型。
-
使用場景:
a. 子類想對父類方法進行增強,一般加一句 super.method();
b. 父類方法是抽象的需要子類進行具體化。
面向對象中的抽象
在繼承中不得不談到抽象,因爲在現實世界中有很多東西的共性的十分抽象的,不能一句話說得清,比如人喫飯、狗喫飯、魚喫飯,他們具體的喫飯行爲大不相同,如果要把“喫飯”這個動作進行提取爲一個公共函數,那麼就必須使用抽象的方法,也就是說只聲明方法名,並聲明爲抽象方法,具體實現我們先不管,等定義具體的實現類時在進行行爲的定義。
-
抽象方法:修飾符 abstract 返回類型 方法名(參數列表)
-
抽象類: abstract class 類名
-
注意事項:
- 將一類事物的共性方法抽取出來,但這個方法說不清道不明,就可以吧這個方法定義爲抽象方法。
- 抽象方法一定要在抽象類中。
- 抽象類中不一定有抽象方法。
- 抽象類可以有成員變量、構造方法、普通方法。
- 抽象類不能直接實例化。
- 抽象類的構造方法是爲了子實現類初始化時構造方法可以調用,用來初始化父抽象類中的成員變量
- 抽象類的子實現類必須重寫父類的全部抽象方法
- 使用場景:一般作爲父類
(三)多態
現實世界中,一種事物有多種形態,比如我們自己,在學校是學生,在家是兒子。
一句話說多態就是:父類對象引用指向子類對象,調用父子共用的方法(子類重寫後的方法)。
- 前提
- 有父子繼承關係(接口實現關係)
- 同名方法的重寫
- 父類引用指向子類對象
父類 對象名 = new 子類()
- 多態的使用步驟
-
定義類
-
定義子類繼承父類,重寫父類方法
-
父類引用指向子類對象–>父類名 對象名 = new 子類() ,調用重寫方法
注意事項:
1.必須有子父類繼承關係(接口,實現類的關係)
2.必須又方法的重寫
3.父類引用指向子類對象–>父類名父類名 對象名 = new 子類() ,調用重寫方法
- 多態中的訪問特點
- 多態中如果出現子類和父類變量同名的訪問:看
=
左邊的類型,是什麼類型就訪問哪個類型的變量 - 多態中如果出現子類和父類方法同名的訪問:看
new
的對象是什麼類型,訪問的就是哪個類型的方法
如果子類中沒有變量或者方法就訪問父類
- 多態和普通面向對象的優點和缺點
- 普通面向對象:
優點:可以訪問父類和本類的所有費私有方法
缺點:擴展性差 - 多態:
優點:擴展性強,尤其在函數參數調用,重寫方法調用上
缺點:不能通過指向子類的引用來使用子類的特有方法
對於多態的缺點,也可以通過向下轉型的方式解決。
- 轉型
- 向上轉型:默認都是向上轉型,也就是父類對象引用指向子類對象
- 向下轉型:
//((Dog) animal).watchDoor();
Dog dog = (Dog) animal;
dog.watchDoor();
通過向下轉型就可以調用子類的特有方法
- 向下轉型可能會拋出異常:Exception in thread “main” java.lang.ClassCastException
對於這個異常可以通過關鍵字instanceof
來解決,在轉型的時候進行判斷,判斷對象是否屬於某個類型。
使用方法:對象名 instanceof 類型