抽象類
基本概念
1、抽象類是含有抽象方法的類。抽象方法沒有方法體,必須用abstract
定義。
abstract class A { // 抽象類
public void fun(){方法體;} // 普通方法
public abstract void print(); // 抽象方法
}
public class Demo {
public static void main(String[] args) {
A a = new A(); // 報錯,A是抽象類,無法實例化
}
}
結果顯示,無法直接實例化抽象類對象.普通類的對象實例化後,該對象可以調用類中的屬性和方法.而抽象類中存在抽象方法,抽象方法沒有方法體無法調用,因此無法產生實例化對象.
2、抽象類使用原則:
(1)抽象類必須有子類;
(2)抽象類的子類(非抽象類時)必須覆寫抽象類中所有的抽象方法(強制子類進行方法覆寫)
(3)抽象類對象的實例化依靠子類完成,採用向上轉型方式。
範例:使用抽象類
abstract class A { // 抽象類
public void fun() { // 普通方法
System.out.println("普通方法");
}
public abstract void print(); // 抽象方法
}
class B extends A {
// 強制要求對抽象方法進行覆寫,否則會報錯
public void print() {
System.out.println("覆寫後的抽象方法");
}
}
public class Demo {
public static void main(String[] args) {
A a = new B(); // 向上轉型
a.fun();
a.print();
}
}
由上述代碼,可知:
(1)抽象類的子類明確要求方法覆寫,而普通類沒有;
(2)抽象類只比普通類多了抽象方法,其他部分相同;
(3)抽象類對象必須經過向上轉型才能實例化;
(4)雖然子類可以繼承任何類,但開發中,普通類最好繼承抽象類。
使用限制
1、抽象類由於存在屬性,因此會有構造方法來初始化屬性。子類對象實例化時依然先執行父類構造方法,再調用子類構造方法。
2、抽象類不能使用final定義,因爲抽象類必須有子類。
3、抽象外部類不允許使用static
定義,而抽象內部類可以使用static
聲明。使用static
定義的抽象內部類相當於抽象外部類,繼承時使用外部類.內部類
的形式表示類名。
abstract class A { // 抽象類
static abstract class B {
public abstract void print();
}
}
class X extends A.B {
public void print() {
System.out.println("*****");
}
}
public class Demo {
public static void main(String[] args) {
A.B ab = new X(); // 向上轉型
ab.print();
}
}
4、static
定義的方法可以沒有實例化對象的情況下直接調用,即使是抽象類中的static方法。
abstract class A { // 抽象類
public static void print() {
System.out.println("static方法");
}
}
public class Demo {
public static void main(String[] args) {
A.print(); // static方法
A a = new A() ; // 報錯
}
}
5、有時抽象類只需要一個特定的子類操作,因此可以將該子類定義爲該抽象類的內部類。
abstract class A { // 抽象類
public abstract void print();
private static class B extends A { // 內部抽象類子類
public void print() {
System.out.println("Hello");
}
}
public static A getInstance() { // 獲取B的實例化對象
return new B();
}
}
public class Demo {
public static void main(String[] args) {
// 客戶端得到抽象類對象時,B對其不可見
A a = A.getInstance();
a.print();
}
}
上述設計在系統類庫中較爲常見,目的是:爲用戶隱藏不需要知道的子類。
6、觀察下述代碼:
abstract class A { // 抽象類
// 1. 先調用父類構造
public A() {
this.print();
}
public abstract void print();
}
class B extends A {
private int num = 100;
// 3.調用子類構造,並初始化num = 30.運行結束,未輸出初始化後的num
public B(int num) {
this.num = num;
}
// 2. 父類構造調用子類的print,此時num = 0,打印輸出。
public void print() {
System.out.println("num = " + num);
}
}
public class Demo {
public static void main(String[] args) {
new B(30); // 4. 結果爲0
}
}
在構造方法執行完之前,屬性的內容均爲其對應的數據類型的默認值。子類在執行構造方法前必先執行父類的構造方法,因爲此時子類構造方法還沒執行,就調用print()
輸出了num的值,所以num爲0
.
模板設計模式
要求:設計三個類,通過類描述如下行爲:
(1)機器人:充電、工作;
(2)人:喫飯、工作、睡覺;
(3)豬:喫飯、睡覺
思路:定義一個抽象類,具有喫飯、睡覺、工作的抽象方法。根據子類的不同,具體實現抽象方法。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-9Oy51FpX-1570848167779)(/18-2.png “思路圖”)]
abstract class Action {
public static final int EAT = 1;
public static final int SLEEP = 5;
public static final int WORK = 7;
public void command(int flag) {
switch (flag) {
case EAT:
this.eat();
break;
case SLEEP:
this.sleep();
break;
case WORK:
this.work();
break;
case EAT + WORK:
this.eat();
this.work();
break;
}
}
// 不確定方法中的具體行爲,定義爲抽象類
public abstract void eat();
public abstract void sleep();
public abstract void work();
}
定義子類:
class Robot extends Action {
public void eat() {
System.out.println("機器人正在補充能量");
}
public void sleep() {
}
public void work() {
System.out.println("機器人正在工作");
}
}
class Human 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() {
}
}
範例:測試程序
public class Demo {
public static void main(String[] args) {
fun(new Robot());
fun(new Human());
fun(new Pig());
}
public static void fun(Action act) {
act.command(Action.EAT);
act.command(Action.SLEEP);
act.command(Action.WORK);
}
}
結果顯示:子類要實現操作,必須按照Action類的標準。