摘要:抽象類作為多個子類的通用模板,子類在抽象類的基礎上進行擴展改造,但子類總體上會大致保留抽象類的行為方式。稍微專業一點的定義就是模板方法模式,在一個方法中定義一個算法的骨架,而將一些步驟延遲到子類中。
抽象方法和抽象類
抽象類:用abstract修飾符修飾的類,如:
public abstract class GeneralService { }
抽象方法:用abstract修飾符修飾的方法,抽象方法不能有方法體,如:
public abstract void service();
抽象類和抽象方法的規則如下:
必須用abstract修飾符修飾
抽象類不一定包含抽象方法,但含有抽象方法的類一定是抽象類
抽象類不能被實例化
抽象類的構造器不能用于創建對象,主要是用于被其子類調用
下面定義一個Shape抽象類:
/** * 定義一個抽象類,用于描述抽象概念的“形狀” */ public abstract class Shape { // 形狀的 顏色 private String color; public String getColor() { return color; } public void setColor(String color) { this.color = color; } // 帶參構造器 public Shape(String color) { this.color = color; } // 定義一個計算周長的抽象方法 public abstract double calPerimeter(); }
上面的Shape類中包含了一個抽象方法calPerimeter(),所以Shape類只能是抽象類。Shape類中既包含初始化塊,又包含構造器,不過這些都不是在創建Shape對象時被調用的,而是在創建其子類對象時被調用。
下面定義一個Triangle類和一個Circle類,讓他們繼承Shape類,并實現Shape中的抽象方法calPerimeter()。
/** * 定義一個三角形類,繼承自形狀類 */ public class Triangle extends Shape { // 定義三角形的三條邊 private double a; private double b; private double c; public Triangle(String color, double a, double b, double c) { super(color); this.a = a; this.b = b; this.c = c; } @Override public double calPerimeter() { return a + b + c; } }
/** * 定義一個圓形類,繼承自形狀類 */ public class Circle extends Shape { // 定義圓的半徑 private double radius; public Circle(String color, double radius) { super(color); this.radius = radius; } @Override public double calPerimeter() { return 2 * Math.PI * this.radius; } }
Shape(形狀)類是一個抽象的概念,Triangle(三角形)類和Circle(圓形)類是Shape的具象,它們都各自實現了Shape的calPerimeter()方法,兩者計算周長的公式不一樣。
下面是測試類:
/** * 測試類 */ public class Test { public static void main(String[] args) { Shape s1 = new Triangle("黃色", 3.0, 4.0, 5.0); Shape s2 = new Circle("紅色", 3); System.out.println("三角形s1的顏色:" + s1.getColor() + ",周長:" + s1.calPerimeter()); System.out.println("圓形s2的顏色:" + s2.getColor() + ",周長:" + s2.calPerimeter()); } }
輸出結果:
三角形s1的顏色:黃色,周長:12.0 圓形s2的顏色:紅色,周長:18.84955592153876
當使用abstract修飾類時,表明這個類是抽象類,只能被繼承;當使用abstract修飾方法時,表明這個方法必須由其子類實現(重寫)。
final修飾的類不能被繼承,final修飾的方法不能被重寫,因此final和abstract不能同時使用。
當使用static修飾一個方式時,表示這個方法是類方法,可以通過類直接調用而無需創建對象。但如果該方法被定義成抽象的,則將導致通過該類來調用該方法時出現錯誤(調用了一個沒有方法體的方法肯定會引起錯誤),因此,static和abstract不能同時修飾某個方法。
abstract關鍵字修飾的方法必須由其子類重寫才有意義,因此abstract方法不能定義成private訪問權限,即private和abstract不能同時修飾某個方法、
抽象類的作用抽象類是從多個具體類中抽象出來的父類,它具有更高層次的抽象,描述了一組事物的共性。
抽象類作為多個子類的通用模板,子類在抽象類的基礎上進行擴展、改造,但子類總體上會大致保留抽象類的行為方式。
模板方法模式如果編寫一個抽象父類,父類提供了多個子類的通用方法,并把一個或多個方法留給其子類去實現,這就是模板模式,是一種十分常見且簡單的設計模式。
稍微專業一點的定義就是:
模板方法模式,在一個方法中定義一個算法的骨架,而將一些步驟延遲到子類中。模板方法使得子類可以在不改變算法結構的情況下,重新定義算法中的某些步驟。
下面再介紹一個模板方法模式的范例,在這個范例中,我們把做菜這個過程分為三個步驟:
備料
烹制
裝盤
這三部就是算法的骨架。然而做不同的菜,需要備的料,烹制的方法,以及如何裝盤都是不同的,做不同的菜時,需要有不一樣的實現。
先來寫一個抽象的做菜父類,代碼如下:
/** * 定義做菜抽象類 */ public abstract class DodishTemplate { /** * 模板方法,封裝了做菜的算法 * 用final關鍵字進行修飾,避免子類修改算法的順序 * 模板方法定義了一連竄的步驟,每一個步驟由一個方法代表 */ protected final void dodish(){ this.preparation(); this.doing(); this.sabot(); } /** * 備料 */ public abstract void preparation(); /** * 烹制 */ public abstract void doing(); /** * 裝盤 */ public abstract void sabot(); }
下面再定義做番茄炒蛋類和做紅燒肉類并實現父類中的抽象方法:
/** * 做番茄炒蛋類 */ public class EggsWithTomato extends DodishTemplate{ @Override public void preparation() { System.out.println("洗并切西紅柿,打雞蛋。"); } @Override public void doing() { System.out.println("雞蛋倒入鍋里,然后倒入西紅柿一起炒。"); } @Override public void sabot() { System.out.println("將炒好的番茄炒蛋裝入碟子里,撒上香蔥。"); } }
/** * 做紅燒肉類 */ public class Bouilli extends DodishTemplate{ @Override public void preparation() { System.out.println("切豬肉和土豆。"); } @Override public void doing() { System.out.println("將切好的豬肉倒入鍋中炒一會然后倒入土豆連炒帶燉。"); } @Override public void sabot() { System.out.println("將做好的紅燒肉盛進碗里,撒上白芝麻"); } }
在測試類中我們來做菜:
public class App { public static void main(String[] args) { DodishTemplate eggsWithTomato = new EggsWithTomato(); eggsWithTomato.dodish(); System.out.println("-----------------------------"); DodishTemplate bouilli = new Bouilli(); bouilli.dodish(); } }
運行結果:
洗并切西紅柿,打雞蛋。 雞蛋倒入鍋里,然后倒入西紅柿一起炒。 將炒好的番茄炒蛋裝入碟子里,撒上香蔥。 ----------------------------- 切豬肉和土豆。 將切好的豬肉倒入鍋中炒一會然后倒入土豆連炒帶燉。 將做好的紅燒肉盛進碗里,撒上白芝麻
從這個案例我們可以看到,DodishTemplate類里定義了做菜的通用算法,而一些具體的實現細節則推遲到了其子類(EggsWithTomato和Bouilli)中。也就是說,模板方法定義了一個算法的步驟,并允許子類為一個或多個步驟提供實現。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/74189.html
摘要:是一種典型的面向對象編程語言。這篇文章主要是來初步理解一下面向對象的思維為下面的內容先給一個基礎。針對面向對象編程的更多內容,會在后面的文章里面詳細解釋。他們都稱之為對象。之后,我們再用編程語言,把這種映射編寫出來,就是的面向對象編程啦。 showImg(https://segmentfault.com/img/remote/1460000012983458?w=900&h=500);...
摘要:如果一個非抽象類遵循了某個接口,就必須實現該接口中的所有方法。抽象類是對整個類整體進行抽象,包括屬性行為,但是接口卻是對類局部行為進行抽象。因此最好的解決辦法是單獨將報警設計為一個接口,包含行為設計為單獨的一個抽象類,包含和兩種行為。 一、抽象類 二、接口 三、抽象類和接口的區別 一、抽象類 在了解抽象類之前,先來了解一下抽象方法。抽象方法是一種特殊的方法:它只有聲明,而沒有具體的實現...
摘要:很多常見的面試題都會出諸如抽象類和接口有什么區別,什么情況下會使用抽象類和什么情況你會使用接口這樣的問題。在討論它們之間的不同點之前,我們先看看抽象類接口各自的特性。抽象類抽象類是用來捕捉子類的通用特性的。 很多常見的面試題都會出諸如抽象類和接口有什么區別,什么情況下會使用抽象類和什么情況你會使用接口這樣的問題。本文我們將仔細討論這些話題。 在討論它們之間的不同點之前,我們先看看抽象類...
閱讀 2577·2021-11-25 09:43
閱讀 1849·2021-09-22 15:26
閱讀 3697·2019-08-30 15:56
閱讀 1702·2019-08-30 15:55
閱讀 1889·2019-08-30 15:54
閱讀 805·2019-08-30 15:52
閱讀 3135·2019-08-29 16:23
閱讀 886·2019-08-29 12:43