1. 程式人生 > 其它 >面向物件(13-1):抽象類

面向物件(13-1):抽象類

面向物件(13):抽象類

1、抽象的表述

我們之前所說的貓,狗,豬,羊駝,熊貓等等都是動物的具體的例子,而動物本身是一個抽象的概念,
而我們之前是將動物寫成了一個類,而類又可以建立物件,但是呢,實際上抽象的東西本身應該不能例項化,
並且動物這個概念中吃的方法,以及動物共有的方法本身也是一個不具體的方法,我們在今天之後,
把一個不具體的功能,叫做抽象方法,而如果說一個類中包含有抽象方法的時候,這個類叫做抽象類。

2、抽象類的特點

(1)抽象類和抽象方法 要用abstract關鍵字修飾

abstract修飾類:放在class前面
            舉例:
                abstract class Animal3{}
abstract修飾方法:放在訪問許可權修飾符的後面
            舉例:
                public abstract void eat();
                抽象方法沒有方法體(沒有大括號{}),直接以分號結尾

(2)有抽象方法的一定是抽象類,但抽象類中不一定有抽象方法(抽象類中只含有具體的成員方法也是可以的);
具體的類中不能有抽象方法,否則會直接報錯

案例:
//動物本身是抽象的概念,不能寫成具體的東西
//建立一個抽象類
abstract class Animal22{  //abstract修飾類的時候,abstract要放在class前面

    //動物的吃也是一個抽象的,不能寫具體的怎麼吃
    //建立一個動物吃的抽象方法
 public abstract void eat();//abstract修飾方法的時候,abstract放在訪問許可權修飾符的後面
                            //而且抽象方法沒有方法體,大括號{}去掉
    //建立一個具體實現方法
    public void fun(){
        System.out.println("這是抽象類中的具體實現的fun方法");
    }
}
/*
	抽象類中,既可以包含抽象方法,也可以包含具體實現的方法(非抽象方法),不會報錯
*/

錯誤案例:
    //建立一個具體的狗類
    class Dog {
        //單獨在具體的類中建立抽象方法
        public abstract void show();//這樣寫 會報錯
    }

(3)如果繼承抽象類的是一個具體的類,要重寫抽象類所有的抽象方法

錯誤案例:
//建立一個具體的狗類,繼承抽象類Animal22
class Dog extends Animal22{	//這樣寫會直接報錯
}

正確案例:上面如果想要不報錯,要重寫抽象類所有的抽象方法
/建立一個具體的狗類,Animal22
class Dog extends Animal22{
//繼承抽象類的是一個具體的類,要重寫抽象類所有的抽象方法
//重寫抽象類中的抽象方法,快捷鍵 游標放在類名上,按住Alt+Enter,選擇Implement methods回車
    @Override
    public void eat() {
        System.out.println("狗吃肉");//自己新增一個輸出語句
    }


如果是一個抽象類繼承抽象類,不需要重寫抽象類中的方法

//建立一個抽象類Demo1,來繼承抽象類Animal22
abstract class Demo1 extends Animal22{
    //抽象類繼承抽象類,類中什麼也不寫,不會報錯
}

(4)抽象類不能被例項化(就是說在測試類中,不能直接建立物件來呼叫抽象類中具體的方法)

既然不能被例項化,那寫在抽象類中具體的方法怎麼去呼叫呢?抽象類如果建立呢?

即:利用多型的形式,通過具體的子類例項化去呼叫方法

案例:想要調取抽象類中的fun方法

//動物本身是抽象的概念,不能寫成具體的東西
//建立一個抽象類
abstract class Animal22{    //abstract修飾類的時候,abstract要放在class前面

    //動物的吃也是一個抽象的,不能寫具體的怎麼吃
    //建立一個抽象方法
    public abstract void eat();//abstract修飾方法的時候,abstract放在訪問許可權修飾符的後面
                                //而且抽象方法沒有方法體,大括號{}去掉
    //建立一個具體實現方法
    public void fun(){
        System.out.println("這是抽象類中的具體實現的fun方法");
    }
}

//建立一個具體的狗類,繼承抽象類
class Dog extends Animal22{
//繼承抽象類的是一個具體的類,要重寫抽象類所有的抽象方法
//重寫抽象類中的抽象方法,快捷鍵 游標放在類名上,按住Alt+Enter,選擇Implement methods回車
    @Override
    public void eat() {
        System.out.println("狗吃肉");//自己新增一個輸出語句
    }
}

//測試類
public class AbstractDemo1 {
    public static void main(String[] args) {
    //抽象類中,不能直接建立抽象類物件,來調取抽象類中具體的方法
    //要利用多型的形式,通過具體的子類例項化去呼叫方法
    //使用抽象多型的形式建立物件(父類引用指向子類物件)
        Animal22 a = new Dog();
        a.fun();//可以呼叫抽象類中具體實現的fun方法
        a.eat();//可以呼叫具體狗類中的eat方法
    }
}

3、抽象類多型的案例

/*
    在抽象的動物類中定義兩個抽象方法,吃飯和睡覺
    分析:
        1、建立一個抽象類:動物類
        2、定義吃飯和睡覺的抽象方法

        想要最終列印輸出吃飯和睡覺,必須建立具體的類來繼承抽象類,
        然後通過使用抽象類多型建立物件(父類引用指向子類物件)
        來調取具體的類中的方法
 */


//建立一個抽象類:動物類
abstract class Animal66{
    //定義吃飯和睡覺抽象方法
    public abstract void eat();
    public abstract void sleep();
}

//建立一個具體的類來繼承抽象類
class Cat extends Animal66{
    //繼承抽象類需要重寫抽象類的所有抽象方法 快捷鍵 Alt+Enter回車
    @Override
    public void eat() {
        System.out.println("貓吃飯");
    }

    @Override
    public void sleep() {
        System.out.println("貓睡覺");
    }
    //我們自己給貓新增一個特有的方法:抓老鼠
    public void catchMouse(){
        System.out.println("貓抓老鼠");
    }
}

//測試類
public class AbstractDemo2 {
    public static void main(String[] args) {
        //使用抽象多型建立物件
        Animal66 a = new Cat();
        //調取具體類中的抽象方法
        a.eat();
        a.sleep();

        //如果想要調取具體類中特有的方法
        //則需要多型向下轉型
        Cat c =(Cat)a;
        //向下轉型後再呼叫特有的方法
        c.catchMouse();
    }
}

4、抽象類的成員特點

(1)抽象類中的成員變數:可以是變數,也可以是常量

abstract class Animal{
    public int a;
    public final int b = 20;
}

(2)抽象類中的構造方法:有構造方法,但是抽象類不能例項化

那構造的意義是什麼呢?要想初始化子類,就必須先初始化父類,在繼承的關係中有用

abstract class Animal{
    public int a;
    //手動建立構造方法
    Animal(){
        a = 20;
        System.out.println(a);
    }
}
//建立一個具體的類繼承抽象 類
class Dog extends Animal{
}

//測試類
public class AbstractDemo{
    public static void main(String[] args) {
    	//建立Dog類的物件
        Dog d = new Dog();
    }
}
        執行結果是:
                20

                Process finished with exit code 0
                /*
                	在具體的類中並沒有語句體,但是建立物件後仍可以輸出20;
                	這說明要想初始化子類,就必須先初始化父類,在繼承的關係中有用
                	所有執行的時候呼叫了抽象類的構造方法
                */

(3)抽象類中的成員方法

可以有抽象方法 限定子類必須完成某些動作;

也可以有非抽象方法 提高程式碼服用性