面向對象的三大特性——封裝 、繼承、多態
一. 面向對象特征:封裝性
1.JAVA中的數據類型
JAVA中所有的數據類型分為兩種
一種為值類型,值類型的變量存儲的就是數據本身,所有的基本數據類型都是值類型
另外一種稱為“引用類型”,或者對象類型,引用類型的變量中存儲的不是數據而是地址
2.實例方法說明
屬性對於每個對象來說各持一份,方法本質是一段可被執行的代碼,方法對於該類型的所有對象來說共享一份
可以在實例方法的方法體中通過關鍵字this訪問調用方法的當前對象
實例方法中訪問當前對象的屬性值this.可以省略
3.成員變量和局部變量的區別
局部變量:定義在方法中的變量
成員變量:定義在類中的變量(類的屬性) 或者稱為實例變量
- 定義的位置不同
- 作用范圍不同:局部變量只能在定義的當前方法內被訪問 而成員變量可以在當前類的所有方法中被訪問
- 默認值不同:局部變量定義完成后沒有自動初始化功能 成員變量在分配完空間只有由系統自動根據變量的類型進行初始化
int--->0 double--->0.0 char---->'\0' String---->null (引用類型數據) boolean---->false
-
生命周期不一樣
局部變量在方法被調用時分配空間,在方法執行結束后立馬銷毀
成員變量在每次new對象的時候分配空間,在對象稱為垃圾的時候被銷毀(由GC來完成的)
注意:當一個類中方法的局部變量和當前類中的成員變量同名了,按照就近原則優先訪問方法中定義的局部變量,如果非要訪問同名的成員變量則需要在變量名前加上一個this.限定
4.方法的重載 overload
定義:方法重載指的是在同一個類中可以出現多個同名的方法,但是參數列表不同,這樣就形成了方法的重載
在調用時自動根據傳入的參數匹配到某個具體的方法進行調用
注意:方法的重載之和方法名以及方法的形參有關
要求:
1.方法名必須相同
2.參數列表不同:參數的個數不同 類型不同 順序不同 ,參數名不能作為參數的區分標志
3.和返回類型無關
使用方法重載的好處:對於調用者來說只需要記住一個方法名即可,調用時會自動的根據傳入的實參找到對應的方法執行
5.類中的構造方法
構造方法是類中的一種特殊方法,和普通方法不一樣:
- 從功能上來,普通的方法主要是用來實現軟件的業務功能,而構造方法關注的當前類的對象創建
- 從定義了說,構造方法的定義有兩個特殊點:1.方法名和類同名 2.方法無返回類型 連void都不能寫
- 從調用來說:普通的方法的調用格式:對象名.方法名(參數列表); 構造方法只能使用new關鍵字進行調用
類中的構造方法的作用就是用來創建該類的對象,如果一個類中沒有構造方法則該類將無法創建對象
規則:當一個類沒有顯示的定義構造方法,則編譯器會自動為這個類添加一個無參並且方法體為空的構造方法
無參構造器負責將對象所占的堆中的空間分配下來,但是只能按照默認的方式對對象屬性進行初始化
如果我們自己在類中定義了構造方法,則編譯器就不會再為這個類提供一個無參的構造方法了
所有對象都是通過調用構造方法構造出來的
6.封裝性
封裝:對象的屬性應該是對象私有的東西
如何對類中的屬性進行封裝的處理?
1.只要在定義類的屬性時加上一個訪問修飾private 私有的即可,
2.同時對外提供針對這些屬性訪問的get和set方法
get方法用來獲取某個屬性的值 set方法用於在類的外部修改某個屬性的值
被private 修飾的屬性只能在本類的內部被訪問
快速為私有的屬性提供get和set方法:alt+shift+s
根據業務的需要我們可以為某個屬性對外只提供get不提供set,那么這樣的屬性稱為“只讀”屬性
相反如果一個屬性只有set沒有get,這樣的屬性稱為只寫屬性
如果在本類的一個方法中去調用另一個方法直接寫:方法名() 前面省略了this.
對象的方法一般是公開的,如果對於類中的某個方法不希望外界直接調用也可以使用private關鍵字進行修飾,那么此時這個方法只能在本類的其他方法中調用
如何設計一個JAVA類:
public class 類名{
//私有屬性的定義;
//get和set方法
//構造方法(建議在每個類中都要提供一個無參的構造器)
//普通方法
}
補充:this關鍵字的兩種用法:
1.在類的方法體中可以使用this.來引用調用這個方法的當前對象,構造方法中的this.指的是當前創建的這個對象
2.普通方法相互之間可以調用,構造方法之間也可以相互調用 (了解)
this(參數)
public Person() {
//this("aaa", 19);
System.out.println("無參構造...");
}
public Person(String name,int age) {
this.name=name;
this.age=age;
System.out.println("有參構造....");
}
注意:在一個構造方法中調用類的另一個構造方法,調用語句必須寫在第一行
二. 面向對象特征之二:繼承性
1.為什么要有繼承?
多個類中存在相同屬性和行為時,將這些內容抽取到單獨一個類中, 那么多個類無需再定義這些屬性和行為,只要繼承那個類即可。
作用:繼承的出現減少了代碼冗余,提高了代碼的復用性。繼承的出現,更有利於功能的擴展。 繼承的出現讓類與類之間產生了關系,提供了多態的前提。
2.關於繼承的規則:
類繼承語法規則:
class Subclass extends SuperClass{ }
-
子類繼承了父類,就繼承了父類的方法和屬性。
-
在子類中,可以使用父類中定義的方法和屬性,也可以創建新的數據和 方法。
-
在Java 中,繼承的關鍵字用的是“extends”,即子類不是父類的子集, 而是對父類的“擴展”。
-
子類不能直接訪問父類中私有的(private)的成員變量和方法。
-
Java只支持單繼承和多層繼承,不允許多重繼承 一個子類只能有一個父類 一個父類可以派生出多個子類
問題:父類構造方法有沒有被繼承到?
因為構造方法必須和當前類同名,因此構造方法不能被子類繼承
私有的成員也被繼承到了只是不能在子類中直接訪問
/**
*設計一個程序員類SE包含屬性 姓名 性別 年齡使用的編程語言
*設計一個項目經理類PE包含屬性 姓名 性別 年齡 項目管理年限
*/
public class Employee {
String name;
String gender;
int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void test() {
System.out.println("我是父類中定義的方法。。。");
}
}
/**
*
*程序員類
*/
public class SE extends Employee{
private String language;
public String getLanguage() {
return language;
}
public void setLanguage(String language) {
this.language = language;
}
public SE() {
}
public SE(String name, String gender, int age, String language) {
this.name = name;
this.gender = gender;
this.age = age;
this.language = language;
}
//自我介紹的方法
public void sayHello() {
System.out.println("姓名:"+ name + "性別:" + this.gender + "年齡:" + this.age +"使用的語言:" + this.language);
}
}
3.子類對象的創建內存分析
在調用子類的構造方法之前先調用了父類的構造方法
創建子類對象之前先創建它的父類對象
在一個子類的對象中完整的包含了一個父類對象
在子類構造方法的第一行默認有一條調用父類構造方法的語句 super()
還可以在子類的方法中通過super.的方式引用子類對象中所包含的父類對象
4. super關鍵字的使用
- 可以通過super()顯示的調用父類的構造方法(必須寫在子類構造方法的第一條)
- 還可以在子類的方法中通過super.的方式訪問父類中定義的成員
5. JAVA中的訪問修飾符
在Java中一共提供了四種訪問權限修飾
-
public :公開的 在程序的任何地方都可以被訪問
-
private:私有的 只能在本類中訪問 即使子類中也不能被訪問
-
default: 默認的 表示成員前面沒有寫任何訪問修飾 包級別的訪問權限(本類中可以訪問 同一個包的其他類中也可以訪問)
-
protected:受保護的 本類中 同包中可以訪問 不同包但是有繼承關系
本類 | 本包的其他類 | 不同包的子類 | 不同包也沒有繼承關系 | |
---|---|---|---|---|
private | 可以 | 不可以 | 不可以 | 不可以 |
default | 可以 | 可以 | 不可以 | 不可以 |
protected | 可以 | 可以 | 可以 | 不可以 |
public | 可以 | 可以 | 可以 | 可以 |
6. 繼承的兩大特性
-
單根性:JAVA中一個類最多只能繼承一個父類 但是一個父類下面可以有多個子類,整個JAVA繼承體系是一個樹形結構
JAVA中如果一個類沒有顯示的繼承一個父類,則默認從Object類繼承,Object類是JAVA中根基類
結論:JAVA中的所有類都直接或間接的繼承自Object
Object是一切JAVA類的父類
-
傳遞性: A類繼承了B類 ,B類又繼承了C類 則我們可以說A類也繼承了C類
三. 面向對象特征:多態
1.概念
多態指的是不同的對象在接收到同一個方法調用時自動表現出不同的行為方式
2. 對象的轉型
向上轉型:一個父類的引用可以指向任何一個子類對象 反之是不行的(默認的)
但是通過父類的引用只能訪問到子類對象繼承到的那部分成員
向下轉型:可以將一個指向子類對象的父類引用通過強制的方式轉成子類的引用
類型的轉換並沒有影響對象在堆中的存儲結構,只是改變了棧中的引用(看待一個對象的視角發生了變化)
Employee emp1=new SE("張三", "male", 21, "C#");
SE ss= (SE)emp1;
注意:強制類型轉換只能按照堆中實際的對象類型進行轉換,否則在運行時會拋出 類型轉換異常ClassCastException
JAVA中為了保證程序執行的安全,在強制類型轉換之前可以使用instanceof運算符來對要轉換的對象實際類型進行檢測
if(emp2 instanceof PE) {
PE ss= (PE)emp2;
System.out.println("轉型成功!");
}else {
System.out.println("對象類型不匹配!");
}
3. 對象轉型的實際應用
通過面向對象的方式模擬動物園的飼養員給動物喂食
需求:通過方法的重載實現飼養員可以給多種不同的動物喂食
//通過在Feeder類中提供多個不同的方法重載實現能夠給多種不同的動物喂食
public class Feeder {
//給老虎喂食
public void feed(Tiger tiger) {
System.out.println("正在給老虎喂食...");
tiger.eatMeat();
}
//給狗喂食
public void feed(Dog dog) {
System.out.println("正在給狗喂食...");
dog.eatGT();
}
}
問題:能否在Feeder中通過一個方法就能夠滿足給所有的動物喂食?
public void feed(Animal animal) {
if(animal instanceof Tiger) {
Tiger tiger = (Tiger)animal;
tiger.eatMeat();
}else if(animal instanceof Dog) {
Dog dog=(Dog)animal;
dog.eatGT();
}else if(animal instanceof Cat) {
Cat cat=(Cat)animal;
cat.eatFish();
}
}
使用多態的方式進行處理:
多態的三個條件:
-
要求繼承
-
要有父類引用指向子類對象
-
要有方法的重寫
方法重寫是發生在父子類之間,子類重寫(覆蓋)父類中的方法,重寫的要求:方法名 參數列表 返回類型必須完全一樣
編譯期統一調用父類中的方法,但是在運行期自動調用實際子類的方法
在子類重寫的方法上面可以使用一個注解@override來強制對重寫的語法進行檢查
public class Animal {
public void eat() {
}
}
public class Monkey extends Animal{
@Override
public void eat() {
System.out.println("猴子在吃香蕉..");
}
}
public void feed(Animal animal) {
animal.eat();
}
4.補充:方法的重寫和重載(override/overwrite)
重載(Overload)
定義:重載是在一個類里面,方法名字相同,而參數不同。返回類型可以相同也可以不同。
每個重載的方法(或者構造函數)都必須有一個獨一無二的參數類型列表。
最常用的地方就是構造器的重載。
重載規則:
- 被重載的方法必須改變參數列表(參數個數或類型不一樣);
- 被重載的方法可以改變返回類型;
- 被重載的方法可以改變訪問修飾符;
- 被重載的方法可以聲明新的或更廣的檢查異常;
- 方法能夠在同一個類中或者在一個子類中被重載。
- 無法以返回值類型作為重載函數的區分標准。
重寫(Override)
定義:在子類中可以根據需要對從父類中繼承來的方法進行改造,也稱 為方法的重置、覆蓋。在程序執行時,子類的方法將覆蓋父類的方法。
重寫規則:
-
子類重寫的方法必須和父類被重寫的方法具有相同的方法名稱、參數列表
-
子類重寫的方法的返回值類型不能大於父類被重寫的方法的返回值類型
-
子類重寫的方法使用的訪問權限不能小於父類被重寫的方法的訪問權限
子類不能重寫父類中聲明為private權限的方法
-
子類方法拋出的異常不能大於父類被重寫方法的異常
注意: 子類與父類中同名同參數的方法必須同時聲明為非static的(即為重寫),或者同時聲明為 static的(不是重寫)。因為static方法是屬於類的,子類無法覆蓋父類的方法。
關鍵字:super
在Java類中使用super來調用父類中的指定操作:
- super可用於訪問父類中定義的屬性
- super可用於調用父類中定義的成員方法
- super可用於在子類構造器中調用父類的構造器
注意:
-
尤其當子父類出現同名成員時,可以用super表明調用的是父類中的成員
-
super的追溯不僅限於直接父類
-
super和this的用法相像,this代表本類對象的引用,super代表父類的內存 空間的標識