【阿里雲】Java面向對象開發課程筆記(十六)——抽象類


1 抽象類的定義與使用

實際開發中不要使用一個類去繼承一個已經實現好的類而只能繼承抽象類和接口。
對象多態性的核心本質:方法的覆寫。如果自子類沒有進行指定方法的覆寫,這樣的操作不合乎要求。如果要對子類的方法進行強制的要求,就必須采用抽象類解決。

1.1 抽象類基本概念

抽象類只是在普通類的基礎上擴充了一些抽象方法而已。抽象方法指的是只是聲明而未實現(沒有方法體)的方法,所有的抽象方法要求使用abstract關鍵字定義,並且抽象方法所在的類也必須使用abstract定義類,表示抽象類。
范例:定義一個抽象類

代碼

abstract class A {
  private String msg = "www";  // 屬性
  public void print(){  // 普通方法
      System.out.println(msg);
  }
  // { }為方法體,所有抽象方法不包含方法體
  public abstract void fun(); // 抽象方法
}

抽象類就是比普通類多了一些抽象方法而已。
抽象類中包含有抽象方法,而抽象方法沒有方法體,即:不知道方法的實現,而如果現在產生了實例化對象,則意味着可以調用類中的所有操作。
抽象類適用原則:

  • 所有抽象類必須要有子類;
  • 抽象類的子類(不是抽象類)必須覆寫抽象類中的全部抽象方法;
    • 方法覆寫一定要考慮權限問題:抽象方法可以使用任意權限,盡量都使用public。
  • 抽象類的對象可以通過對象多態性,利用子類為其實例化。

范例:使用抽象類

代碼

abstract class A {
  private String msg = "www";  // 屬性
  public void print(){  // 普通方法
      System.out.println(msg);
  }
  // { }為方法體,所有抽象方法不包含方法體
  public abstract void fun(); // 抽象方法
}
// 一個子類只能夠利用extends來繼承抽象類,所以依然存在有單繼承
class B extends A{ // 定義抽象類的子類
    public void fun(){
        System.out.println("hello world!");
    }
}

public class TestDemo {
    public static void main(String[] args) {
         A a = new B(); // 實例化子類對象
        a.fun(); // 被子類所覆寫過得方法
    }
} // 輸出結果:hello world!

以上操作沒有任何問題,而且也是一種使用最多的形式。
說明:如下使用形式

代碼

abstract class A {
    private String msg = "www";  // 屬性

    public void print() {  // 普通方法
        System.out.println(msg);
    }

    public static A getInstance() {
        class B extends A {
            public void fun() {
                System.out.println("hello world!");
            }
        }
        return new B();
    }
    public abstract void fun(); // 抽象方法
}

public class TestDemo {
    public static void main(String[] args) {
        A a = A.getInstance();
        a.fun(); // 被子類所覆寫過得方法
    }
} // 輸出結果:hello world!

這種模式屬於非正常模式,但是對於一些封裝性是有好處的。

1.2 抽象類使用限制

1.抽象類只是比普通類多了一些抽象方法的定義而已,所以在抽象類之中允許提供有構造方法,並且子類也會遵守子類對象的實例化流程。實例化子類對象前一定要先去調用子類構造方法。

范例:在抽象類中定義構造

代碼

abstract class Person {
    private String name;
    private int age;
    public Person(){
        System.out.println("**********************");
    }
    public abstract String getInfo(); // 抽象方法
}

class Student extends Person{
    private String school;
    public Student(){
        System.out.println("######################");
    }
    @Override
    public String getInfo() {
        return null;
    }
}

public class TestDemo {
    public static void main(String[] args) {
        new Student();
    }
}

輸出結果

**********************
######################

如果父類中沒有無參構造,那么子類就必須通過super()指明要調用的父類構造方法。

代碼

abstract class Person {
    private String name;
    private int age;
    public Person(String name ,int age){
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return this.name;
    }
    public int getAge(){
        return this.age;
    }
    public abstract String getInfo(); // 抽象方法
}

class Student extends Person{
    private String school;
    public Student(String name,int age, String school){
        super(name,age); // 子類構造必須明確的調用父類構造方法
        this.school = school;
    }
    @Override
    public String getInfo() {
        return "[Student] name = " + super.getName() + ", age = " + super.getAge() + ", school = " + this.school;
    }
}

public class TestDemo {
    public static void main(String[] args) {
        Person per = new Student("Jack",25,"NWAFU");
        System.out.println(per.getInfo());
    }
}

輸出結果

[Student] name = Jack, age = 25, school = NWAFU

抽象類中有屬性,所有屬性在對象進行實例化時開辟空間,對象實例化必須使用構造方法,所以抽象類里有構造方法。

對象實例化核心步驟:

  • 進行類的加載;
  • 進行類對象的空間開辟;
  • 進行類對象中的屬性初始化(構造方法)。

代碼

abstract class A{
    public A(){  // 4. 調用父類構造方法
        this.print(); // 5. 調用被子類覆寫過的構造方法
    }
    public abstract void print();  // 抽象方法
}

class B extends A{
    private int num = 100;
    public B(int num){ // 2. 調用子類實例化對象
        super(); // 3. 隱含一行語句,實際要想調用父類構造
        this.num = num; // 8. 為類中的屬性初始化
    }
    public void print(){  // 6. 此時子類對象的屬性還沒有被初始化
        System.out.println(this.num); // 7. 內容為其對應數據的默認值
    }
}

public class TestDemo {
    public static void main(String[] args) {
       new B(30); // 1. 實例化子類對象
    }
}
 // 輸出結果:0

結論:如果構造方法沒有執行,那么對象中的屬性一定都是其對應數據的默認值。
2.抽象類中允許不定義任何的抽象方法,但此時抽象類對象依然無法進行直接實例化處理。
3.抽象類一定不能使用final進行聲明,因為使用final定義的的不能夠有子類,而抽象類一定有子類。

  • 抽象方法不能夠使用private進行定義,因為抽象方法必須被覆寫

4.抽象類也分為內部抽象類和外部抽象類,抽象類可以使用static定義描述為外部抽象類。

范例:觀察內部抽象類

代碼

abstract class A{
   public abstract void printA();
   static abstract class B{
       public abstract void printB();
   }
}
class X extends A{
    public void printA(){};
    class Y extends B {
        public void printB(){}
    }
}

如果外部抽象類上使用了static就是語法錯誤,可內部抽象類上允許使用static。

1.3 抽象類實際應用——模板設計模式

抽象類最大特點在於規定了子類的實現結構,抽象類更多的情況下還可以起到一個模板的作用。

  • 人= 吃飯+睡覺+工作;
  • 豬=吃飯+睡覺;
  • 機器人=吃飯+工作。

假設有一個按鈕控制(方法),一旦傳入了某些指令之后就可以進行相應處理。

代碼

abstract class Action{ // 描述的是一個抽象行為
   public static final int EAT = 1;
   public static final int SLEEP = 5;
   public static final int WORK = 10;
   public void command(int cmd){
        switch (cmd){
            case EAT :
               this.eat();
               break;
            case SLEEP :
                this.sleep();
                break;
            case WORK :
                this.work();
                break;
            case EAT + SLEEP + WORK :
                this.eat();
                this.work();
                this.sleep();
                break;
        }
   }
   // 不確定具體的實現,但是行為應該定義好
   public abstract void eat();
   public abstract void sleep();
   public abstract void work();
}
class Humen extends Action{
    public void eat(){
        System.out.println("人吃熟食,干凈");
    }
    public void sleep(){
        System.out.println("人困了就睡");
    }
    public void work(){
        System.out.println("人要拼搏");
    }
}
class Pig extends Action{
    public void eat(){
        System.out.println("豬在槽子里吃");
    }
    public void sleep(){
        System.out.println("豬圈里睡");
    }
    public void work(){}
}
class Robbot extends Action{
    public void eat(){
        System.out.println("機器人要充電");
    }
    public void sleep(){}
    public void work(){
        System.out.println("機器人不停工作");
    }
}
public class TestDemo {
    public static void main(String[] args) {
        fun(new Humen());
        fun(new Pig());
        fun(new Robbot());

    }
    public static void fun (Action action){
        action.command(Action.EAT + Action.SLEEP + Action.WORK);
    }
}
 ```
> 輸出結果
```shell
人吃熟食,干凈
人要拼搏
人困了就睡
豬在槽子里吃
豬圈里睡
機器人要充電
機器人不停工作
  • 抽象類在實際的使用過程之中會定義一些固化的模式,它只能接收幾種特定的指令
  • 每種指令的具體實現由子類負責完成,父類只做了方法的約定。

2 總結

  1. 抽象類雖然定義了子類必須要做的事情,但抽象類依然存在單繼承局限。
  2. 抽象類的使用必須通過子類進行對象實例化處理。

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com