知識點
-
什么是抽象類
抽象類與普通類主要兩點不同:
1、在類的修飾符后面多了一個abstract關鍵字
2、抽象類是不允許通過new來實例化的
由於抽象類不能通過new來實例化,所以基本上是在繼承中當做父類使用。 -
什么是抽象方法
抽象方法的定義需要加上abstract關鍵字,不能有方法體,以封號結尾,比如:
public abstract void getOtherSalary();
抽象方法的具體實現,需要在子類中實現。注意:static、final的方法,不能被申明為抽象方法。 -
抽象類與抽象方法
抽象類不一定包含抽象方法,但如果一個類包含了抽象方法,那這個類一定是抽象類,否則編譯不通過。 -
什么時候用抽象方法
抽象方法通常用於父類中。父類通常都是用於定義一些公共方法、公共屬性等,但是實際項目可能會出現某些方法定義在父類中,父類卻無法給出具體的實現,此時就是抽象方法出場的時候了。比如下文實例中,職員在公司中的收入都包含基本工資以及績效獎金,基本工資大家都一樣,但是績效獎金就因崗位而異了,所以績效獎金在職員類中只是個方法體,沒有具體實現。 -
抽象方法與設計模式
抽象方法在設計模式中有比較多的體現,特別是用於 模板方法設計模式,詳見下文實例
實例
1.抽象方法的使用
需求描述:公司里的職員分為普通程序員和技術總監,所有職員的基本薪水都是10000元每個月,程序員的績效獎金每個月3000元,技術總監的績效獎金每個月20000元。
了解了需求后,我們先定義一個職員類Employee,如下:
/**
* 定義職工類,每個職工的薪水都由基本薪資跟績效獎金組成
*/
public abstract class Employee {
/**
* 崗位名稱
*/
private String jobName;
/**
* 所有職工的每月基本薪資都一樣
* @return
*/
public int getBaseSalary(){
return 10000;
}
/**
* 所有職工都有績效獎金,但是普通程序員跟技術總監的不一樣,
* 所以這里無法給出具體實現,需要在子類中實現
* @return
*/
public abstract int getOtherSalary();
public String getJobName() {
return jobName;
}
public void setJobName(String jobName) {
this.jobName = jobName;
}
}
定義程序員類Coder,繼承職員類,實現getOtherSalary() 方法,如下:
/**
* 程序員類,繼承Employee類
*/
public class Coder extends Employee{
/**
* 由於繼承了Employee類,所以必須實現Employee類中的抽象方法getOtherSalary()
* @return
*/
@Override
public int getOtherSalary() {
return 3000;
}
}
定義技術總監類Cto,繼承職員類,實現getOtherSalary() 方法,如下:
/**
* 技術總監類,繼承Employee類
*/
public class Cto extends Employee{
/**
* 由於繼承了Employee類,所以必須實現Employee類中的抽象方法getOtherSalary()
* @return
*/
@Override
public int getOtherSalary() {
return 20000;
}
}
最后打印程序員與技術總監每個月的薪水:
public class AbstractMain {
public static void main(String[] args){
Coder coder = new Coder();
coder.setJobName("程序員");
System.out.println(coder.getJobName() + "每個月薪資為:");
System.out.println("基本薪資:" + coder.getBaseSalary() + "元");
System.out.println("績效獎金:" + coder.getOtherSalary() + "元");
Cto cto = new Cto();
cto.setJobName("技術總監");
System.out.println(cto.getJobName() + "每個月薪資為:");
System.out.println("基本薪資:" + cto.getBaseSalary() + "元");
System.out.println("績效獎金:" + cto.getOtherSalary() + "元");
}
}
執行以上程序后,輸出:
程序員每個月薪資為:
基本薪資:10000元
績效獎金:3000元
技術總監每個月薪資為:
基本薪資:10000元
績效獎金:20000元
2.抽象方法與模板方法設計模式
在完成了以上需求后,此時又提出新需求,按照以下格式打印每個月的工資條,並且打印的順序必須按以下格式打印出來:
XXX每個月薪資為:
基本薪資:XXX元
績效獎金:XXX元
該月總工資為:XXX元
按照第一個例子的實現方式無法滿足這個需求,第一個例子的打印順序是由調用者決定的,無法統一控制。此時就是模板方法設計模式登場的時候了。基於第一個例子,改造一下職員類Employee,增加打印工資條的方法public final void printSalary()
如下:
/**
* 定義職工類,每個職工的薪水都由基本薪資跟績效獎金組成
*/
public abstract class Employee {
/**
* 崗位名稱
*/
private String jobName;
/**
* 所有職工的每月基本薪資都一樣
* @return
*/
public int getBaseSalary(){
return 10000;
}
/**
* 所有職工都有績效獎金,但是普通程序員跟技術總監的不一樣,
* 所以這里無法給出具體實現,需要在子類中實現
* @return
*/
public abstract int getOtherSalary();
/**
* 獲取每個月工資總額
* @return
*/
public int getTotalSalary(){
return this.getBaseSalary() + this.getOtherSalary();
}
/**
* 定義執行順序模板,模板中有些方法(抽象方法)是要在子類中實現
* 打印工資條,定義為final類,禁止被子類重寫
*/
public final void printSalary(){
System.out.println(this.jobName + "每個月薪資為:");
System.out.println("基本薪資:" + this.getBaseSalary() + "元");
System.out.println("績效獎金:" + this.getOtherSalary() + "元");
System.out.println("該月總工資為:" + getTotalSalary() + "元");
}
public String getJobName() {
return jobName;
}
public void setJobName(String jobName) {
this.jobName = jobName;
}
}
打印每個月工資條:
public class AbstractMain {
public static void main(String[] args){
Coder coder = new Coder();
coder.setJobName("程序員");
coder.printSalary();
Cto cto = new Cto();
cto.setJobName("技術總監");
cto.printSalary();
}
}
以上執行結果為:
程序員每個月薪資為:
基本薪資:10000元
績效獎金:3000元
該月總工資為:13000元
技術總監每個月薪資為:
基本薪資:10000元
績效獎金:20000元
該月總工資為:30000元