三大特性
- 封裝
- 繼承
- 多態
三大特性:封裝
封裝是什麼
將成員變量私有化,並且提供對應的公共訪問方法
封裝的優點
- 提高代碼的複用性
- 提高代碼的可閱讀性
- 隱藏核心實現的邏輯代碼,簡化外部邏輯,並且阻止來自外部的隨意訪問
- 實現代碼與功能的一對一匹配
封裝的實現
核心:
- 成員變量私有化:private
- 提供公共訪問方法:getter/setter
注意:只有私有化後的成員變量才能叫做屬性
示例:
package day20191103;
public class Demo01 {
private int a;
private int b;
public void Demo01() {
}
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
public int getB() {
return b;
}
public void setB(int b) {
this.b = b;
}
}
實體類的規範
實體類是什麼:具有實際意義的類叫做實體類,又叫JavaBean
實體類有什麼:
- 屬性
- 無參構造器
- getter/setter
JavaBean的規範
- 命名規範:單個單詞首字母大寫,多個單詞的組合遵循駝峯命名法
- 成員變量私有化,提供getter/setter方法
- 提供無參構造器
- 重寫equals()和hashCode()
- 重寫toString()
注意:業務代碼不能寫在實體類中
三大特性:繼承
繼承是什麼
子類繼承父類,子類擁有父類所有(公開的)成員屬性和成員方法(構造器除外),同時子類也可以擁有自己特有的成員屬性和成員方法
注意:
- 若子類自己的成員屬性與父類同名,則父類的成員屬性被覆蓋
- 若子類自己的成員方法與父類同名,則發生方法重寫
繼承的作用
- 提高代碼的複用性
- 提取公共特徵
- 可以在父類的基礎上進行擴展
繼承的使用
關鍵詞:extends
示例:
class Animal{
String name;
int age;
public void sleep(){
}
public void eat(){
}
}
class People extends Animal{
String bitthday;
public void study(){
}
}
public static void main(String[] args){
People p = new People();
p.study();
//子類可以擁有父類的成員變量和成員方法
p.sleep();
}
繼承的特點
-
繼承具有傳遞性,即子類繼承父類的同時,也會繼承父類的父類(爺爺-爸爸-兒子)
-
一個父類可以有多個子類(一個爸爸可以有多個兒子)
-
一個子類只能有一個父類(一個兒子只能有一個爸爸)
-
如果一個類沒有繼承任何類,那麼這個類默認繼承Object類,所以每個類都有父類(每個兒子必定有一個爸爸)
-
結合第一點和第四點,我們可以得知:所有類都繼承了Object類。這個繼承可以分爲兩種:
- 直接繼承:子類直接繼承Object類
class Son extends Object{ //直接繼承 }
- 間接繼承:子類的父類(或最高代)繼承Object類
class Father{ } class Son extends Father{ //子類繼承父類,父類繼承Object類 }
子類內存在堆中的表現形式
子類內存在堆中分爲兩個部分
- 父類對象
- 子類對象
這兩個對象在new操作時被創建,對象中有各自成員屬性與成員方法。在調用成員屬性和成員方法時,遵循就近原則:子類對象中存在同名的屬性或方法時,則調用子類中的屬性和方法;否則,就調用父類對象中的屬性或方法(方法重寫的原理)。
內存示意圖如下:
子類調用父類成員
關鍵字:super
super是什麼
- 表示父類對象,與this用法類似、意義不同
super的作用
- 調用父類(公開的)構造器:super(參數列表)
- 調用父類(公開的)成員屬性:super.屬性名()
- 調用父類(公開的)成員方法:super.方法名()
super調用自身構造器的注意點
- 只能放在構造器中
- 必須是第一行代碼
注意:
- 每一個類的構造器中都有一個隱含的super(),可以被自定義的**super(參數)**覆蓋
- 在子類實例化對象時,一定會在構造自身之前先構造一個父類對象
- 當父類只有有參構造器時,子類構造器將出現錯誤。因此,爲了方便繼承,每一個父類都必須添加無參構造器
三大特性:多態
多態
多態的表現形式
- 重載
- 重寫
多態的前提條件
- 具有繼承關係的父、子類(實現抽象類也算)
方法重載
方法重載的條件
- 同一個類中
- 方法名相同、參數列表不同的方法構成重載
- 參數個數不同
- 參數個數相同,參數類型不同
- 參數個數相同,參數類型相同,相同類型的參數順序不同
注意1:
- 參數列表的異同判斷與參數名稱無關
- 方法重載與返回值類型無關
- 方法重載與訪問控制符無關
- 調用方法時,根據傳入的參數確定調用哪一個重載方法
方法重載的作用
- 提高代碼的複用性
- 提高代碼的閱讀性
- 使代碼更加規範
方法重寫
方法重寫的條件:
- 在子類中(繼承/抽象)
- 返回值類型相同或是父類返回值類型的子類,方法名、參數列表必須相同
- 訪問控制權限不能比父類窄
方法重寫的作用:
- 提高代碼的複用性
- 體現不同對象之間的差異性
示例:
package day20191029;
public class Demo01 {
public static void main(String[] args) {
Son son = new Son();
son.method();
}
}
class Father{
public Father( ) {
}
public void method() {
System.out.println("我是父類方法");
}
}
class Son extends Father{
public Son() {
}
public void method() {
System.out.println("我是子類方法");
}
}
注意:子類調用方法時,遵循就近原則
向上造型
向上造型是什麼:父類類型的引用變量接收子類類型的對象,是多態的體現
- 示例:Father father = new Son();
向上造型中的相關概念
- 編譯時類型:編譯時,編譯器眼中的變量類型(Father father部分)
- 運行時類型:運行時,虛擬機眼中的變量類型(**new Son()**部分 )
編譯器認爲father的類型是Father,但是在運行時,虛擬機認爲father的類型是Son
向上造型中的多態體現
- 編譯時類型決定對象能調用哪些方法:通俗地說,father能"."出Father中的所有方法
- 運行時類型決定對象調用的方法內容:如果father調用的方法在Son中被重寫,則調用Son中的方法;否則,調用Father中的方法
- 示例:
package day20191029;
public class Demo01 {
public static void main(String[] args) {
Father father = new Son();
father.method();//method()在子類中被重寫,所以此時調用的是子類中的方法
}
}
class Father{
public Father( ) {
}
public void method() {
System.out.println("我是父類方法");
}
}
class Son extends Father{
public Son() {
}
public void method() {
System.out.println("我是子類方法");
}
}
注意:只有調用被重寫的方法才能體現多態,如果調用未被重寫的方法,則無法體現多態
向上造型的類型轉換
轉換的條件
- 必須有直接繼承關係
- 運行時類型相同或子類轉換成父類
父類不能轉換成子類,而子類能轉換成父類的原因:子類中除了繼承自父類的成員屬性和成員方法,還有屬於自己的屬性和方法。父類轉換成子類時,引用變量的編譯時類型變成了子類類型,而運行時類型依然是父類類型,由於編譯時類型的特性,轉換後的引用變量能使用子類特有的屬性和方法,但是實際運行時父類中並沒有這些屬性和方法,於是發生了報錯;而子類轉換成父類就沒有這個問題,因爲子類有父類所有(公開的)成員屬性和成員方法。
示例:
package day20191029;
public class Demo01 {
public static void main(String[] args) {
Father father1 = new Son();
Son son1 = (Son)father1;
son1.method();
Son son2 = new Son();
Father father2 = (Father)son2;
//編譯通過,但是運行後拋出ClassCastException
Father father = new Father();
Son son3 = (Son)father;
son3.method2();
}
}
class Father{
public Father( ) {
}
public void method() {
System.out.println("我是父類方法1");
}
public void method2() {
System.out.println("我是父類方法2");
}
}
class Son extends Father{
public Son() {
}
public void method() {
System.out.println("我是子類方法1");
}
}
注意:強制類型轉換屬於編譯時語法,該語法只在編譯時有效,運行時取決於運行時類型。因此纔會發生編譯通過,但是運行報錯。
親子鑑定
關鍵字:instanceof
- 作用:判斷一個引用變量是否屬於某個類型(取決於運行時類型),返回值是布爾類型
- 使用示例:father instanceof Father