Java基礎進階_day03_(抽象類,接口,多態)

Java基礎進階_day03_(抽象類,接口,多態)

1. 抽象類

1.1 抽象方法

抽象方法:沒有方法體(就是沒有那對大括號)的方法稱爲抽象方法.public voidshow();

1.2 抽象類理解

抽象類:含有抽象方法的類必須定義爲抽象類;抽象就是沒有具體的事物,只有類的描述信息,只有出現具體的子類後這些描述信息纔有意義.

1.3 抽象類格式

權限修飾符 abstract class 類名{
    定義類的成員;
}
子類通過繼承抽象類後,實現父類中的抽象方法.

1.4 抽象類特點

# 抽象類必須使用abstract關鍵字修飾;
# 含有抽象方法的類一定是抽象類,抽象類不一定有抽象方法;
# 抽象類有成員變量(常量,變量)和成員方法(抽象,非抽象);
# 抽象類有構造方法,但是抽象類不能被直接實例化(可以通過多態的方式實例化),抽象類的構造方法的作用是被子類調用進行父類成員初始化以便子類使用父類的數據;
# 抽象類的子類(繼承):
 * 當子類爲抽象類時,子類不必重寫父類的抽象方法;
 * 當子類爲普通類時,子類必須重寫父類的所有的抽象方法;

1.5 抽象類注意事項

# abstract修飾符與其他修飾符關係:
 * private:衝突(抽象方法必須被子類重寫,而private修飾的方法子類不能重寫);
 * final:衝突(抽象方法必須被子類重寫,而final修飾的方法子類不能重寫);
 * static:沒有意義(抽象方法是沒有方法體,使用static修飾後可以類名.方法名調用,該方法無意義);
# 當抽象類沒有抽象方法時意義:
 * 限制該類不能被創建對象(可以作爲工具類).

1.6 案例代碼

/*
 * 抽象類案例
 */
public class AbstractDemo {
    public static void main(String[] args) {
        // 抽象類不能被創建對象
        //MyAbstractDemo mad = new MyAbstractDemo();
    }
}
// 定義抽象類
abstract class MyAbstractDemo {
    // 抽象類有成員常量,常量需要定義時或構造方法中進行初始化
    private final String name;
    // 抽象類有成員變量
    private int age;
    // 抽象類有構造方法
    public MyAbstractDemo() {
        name = "張三";
    }
    public MyAbstractDemo(String name) {
        this.name = name;
    }
    // 抽象類有非抽象方法
    public void show() {
    }
    // 抽象類可以有抽象方法
    public abstract void show2();
}
// 抽象類的子類可以爲抽象類
abstract class SonAbstract extends MyAbstract {
    // 子類不必重寫父類的抽象方法;
}
// 抽象類的子類可以爲具體類
class SonAbstract2 extends MyAbstract {
    // 必須實現父類中的所有抽象方法
    public void show2(){}
}

2. 接口

接口是功能的集合,是類的功能擴展;接口不是一個類,是一種較爲特殊的”類”.

2.1 接口格式

# 使用interface關鍵字修飾,且沒有class關鍵字
interface 接口名{
    定義靜態常量及抽象方法;
}
# 類實現接口: 
public class 類名 implements 接口名{
    實現接口中的抽象方法;
}

2.2 接口特點

# 接口使用interface關鍵字修飾;
# 接口可以有成員變量:成員變量只能是靜態常量,默認都有public static final關鍵字修飾(定義時加上);
# 接口有成員方法:成員方法只能是抽象方法,方法默認都有public abstract關鍵字修飾(定義時加上);
# 接口沒有構造方法,不能被創建對象,也不需要進行初始化(接口的所有成員變量均是靜態的,不需要進行初始化), 接口可以使用多態的方式進行實例化(創建對象);
# 接口子類:
 * 當子類爲抽象類時,不需要重寫接口中的抽象方法;
 * 當子類爲具體類時,需要實現接口的所有抽象方法.

2.3 接口注意事項

# 當類C繼承A類同時實現接口B,如果類A中和接口B中有相同的方法且A類中方法爲非抽象方法:
    C類可以不用重寫接口中方法;
    C類重寫了類A中的方法,也同時將接口B中方法抽象進行了重寫(子類繼承父類後,獲取了父類的成員方法,相當於重寫了接口中抽象方法);
    class A {
    public void method() {
    }
    }
    interface B {
    public abstract void method();
    }
    class C extends A implements B {
    //如果不重寫method()方法,使用的是A中的method()方法
    //如果重寫method()方法將同時重寫A和接口B中的method()方法
    }
# 接口不是類,沒有父類;
# 類實現多個接口時只能有一個implements關鍵字,接口名間使用逗號隔開.

2.4 類與類,類與接口,接口和接口的關係

# 類與類:繼承關係,只能單繼承,不能多繼承,可以多層繼承,不能循環繼承;
# 類與接口:實現關係,類能實現一個或多個接口,並在繼承一個類的同時實現多個接口;
# 接口與接口:繼承關係,可以單繼承,可以多繼承.

案例代碼

/*
 * 類,接口間的關係
 */
public class ClassAndInterface {
}
/*
 * 類與類的關係:繼承關係
 */
// 定義類A
class A {}
// 定義類B
class B extends A{
    // 1.類支持單繼承
}
// 定義類C
//class C extends A,B{} 2.類不支持多繼承
class C extends B{
    // 3.類支持多層繼承
}
// 4.類不能循環繼承
//class D extends F{}
//class F extends D{}
/*
 * 類與接口的關係:實現關係
 */
interface InterA {}
interface InterB {}
// 1.類實現接口,可以單實現
class ClassA implements InterA {}
// 2.類實現接口,可以多實現
class ClassB implements InterA,InterB {}
// 3.類繼承的同時單/多實現接口
class ClassC extends ClassA implements InterA,InterB {}
/*
 * 接口與接口的關係:繼承關係
 */
// 1.可以單繼承
interface InterC extends InterA {}
// 2.可以多繼承
interface InterD extends InterA, InterB{}

2.5 抽象類與接口的區別

# 成員變量的區別:
  * 抽象類的成員變量:可以爲常量,可以爲變量
  * 接口的成員變量:只能爲靜態的常量
# 構造方法區別:
  * 抽象類的構造方法:有構造方法,不能被實例化(子類訪問父類成員時需先將父類成員進行初始化,通過調用父類的構造方法進行父類成員的初始化)
  * 接口的構造方法:沒有構造方法,不能被實例化(接口的成員變量均爲常量,不需要進行初始化)
# 成員方法的區別:
  * 抽象類的成員方法:可以是非抽象,也可以是抽象
  * 接口的成員方法:只能是抽象方法
# 關係區別:
  * 抽象類是類,遵循類的特點(類與接口遵循類與接口的關係)
# 設計理念區別:
  * 抽象類-->被繼承體現的是:"is a"的關係。抽象類中定義的是該繼承體系的共性功能,抽象類就是當作普通類使用,只不過是繼承時強制子類實現抽象方法並且不能創建實例對象.
  * 接口-->被實現體現的是:"like a"的關係。接口中定義的是該繼承體系的擴展功能。
接口是類的擴展功能定義的集合,類需要擴展額外的功能時,就實現具有該功能的接口.

3. 多態

多態: 對象在不同的時刻表現出不同的狀態.

3.1 多態前提

# 繼承關係或實現接口的關係存在;
# 方法的重寫(可以沒有方法重寫,當沒有方法重寫時,沒有意義);
# 父類(接口)引用指向子類對象.

案例代碼

/*
 * 多態現象
 */
public class Demo01 {
    public static void main(String[] args) {
        // 父類引用指向子類對象
        Father f = new Son();
        // 成員方法編譯看左邊,運行看右邊(子類的方法)
        f.show();   // Son show
        f.show2();  // Son show2
        // 子類沒有重寫父類方法,調用父類本身的方法
        f.show3();  // Father show3
    }
}
abstract class Father {
    public void show() {
        System.out.println("Father show");
    }
    public abstract void show2();
    public void show3() {
        System.out.println("Father show3");
    }
}
class Son extends Father {
    public void show() {
        System.out.println("Son show");
    }
    // 重寫父類的方法
    @Override
    public void show2() {
        System.out.println("Son show2");
    }
}

3.2 多態的好處

# 提高了程序的維護性(繼承體現);
# 提高了程序的擴展性(多態體現,父類作爲方法的形式參數,子類對象作爲方法調用時的實際參數).

案例代碼

/*
 * 多態提高代碼的擴展性
 */
public class Demo02 {
    public static void main(String[] args) {
        // 測試Animal所有子類的sleep()方法
        testSleep(new Dog());   // 狗在睡覺
        testSleep(new Cat());   // 貓在睡覺

        // 當Animal再有一個子類要測試sleep()方法時
        // 可以直接調用testSleep()方法測試新的子類的slee()方法,這就是代碼的擴展性
        // testSleep(new Pig());
    }
    // 定義調用Animal子類的sleep()的方法
    public static void testSleep(Animal animal) {
        animal.sleep();
    }
}
// 動物類,所有動物的父類
class Animal {
    public void sleep() {
        System.out.println("動物睡覺");
    }
}
// 狗類
class Dog extends Animal {
    // 重寫父類的方法
    @Override
    public void sleep() {
        System.out.println("狗在睡覺");
    }
}
// 貓類
class Cat extends Animal {
    // 重寫父類的方法
        @Override
        public void sleep() {
            System.out.println("貓在睡覺");
        }
}

3.3 多態的弊端

# 父類引用指向子類對象,父類引用不能調用子類特有的方法.
 * 解決方法:多態的向下轉型:
        父類  fu = new 子類();
        子類  zi = (子類)fu;

3.4 多態中的成員訪問特點

# 多態中成員訪問特點: 父類  fu = new 子類();
  * 成員變量:編譯看左邊,執行看左邊(父類的引用,調用的是父類的成員變量);
  * 構造方法:子類創建對象時將父類的成員進行初始化;
  * 成員方法:編譯看左邊,執行看右邊(方法被子類重寫,所以執行看右邊);
  * 靜態方法:編譯左邊,執行看左邊(靜態方法和類直接相關,子類中的方法不是重寫父類的靜態方法).

3.5 多態其他注意事項

多態分類

# 具體類多態:父類是具體的類;
# 抽象類多態:父類爲抽象類;
# 接口多態:子類實現的是接口(應用較多).

多態轉型

# 向上轉型:多態本身就是向上轉型(子類轉換爲父類對象);
# 向下轉型:要注意一定能夠轉換爲相應的子類對象,否則會報錯(ClassCastException類型轉換異常).
    父類  fu = new 子類();
    子類  zi = (子類)fu;

instanceof關鍵字

# 用於判斷某個對象是不是某一個數據類型,如果是則返回true,否則返回false, 一般用於判斷多態中向下轉型.
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章