1. 程式人生 > >Java基礎知識回顧之抽象類

Java基礎知識回顧之抽象類

簡介

如果是需要了解抽象類,就需要知道什麼普通類。對於普通類,可以直接產生例項化物件,並且在普通類之中可以包含有構造方法、普通方法、static 方法、常量、變數等內容。而所謂的抽象類就是指在普通類的結構中增加抽象方法的組成部分。

在所有的普通方法上都會有一個“{}”,這個表示方法體,有方法體的方法一定可以被物件直接使用。而抽象方式是沒有方法體的方法,同時抽象方法還必須使用 abstract 關鍵字進行定義。

擁有抽象方法的類一定屬於抽象類,抽象類要使用 abstract 關鍵字宣告。

程式碼例項說明

定義抽象類

使用 abstract 關鍵字來宣告類以及方法,抽象方法是不能有方法體的。

abstract class A{	// 定義一個抽象類
	
	public void fun() {		// 普通方法
		System.out.println("這是一個普通方法");
	}
	
	// 此方法沒有方法宣告,並且使用 abstract 關鍵字,表示抽象類
	public abstract void print();
	
}

使用抽象類

由於抽象類不能直接被例項化,比如上面的例子中,使用 A a = new A() 就會報 A是抽象類,不能被例項化的錯誤。

原因:當一個類的例項化物件之後,就意味著這個例項化物件可以呼叫類中的屬性和方法,但是在抽象類中存在有抽象方法,抽象方法是沒有方法體,是不能被呼叫的

,真是因為不能呼叫這個方法,在例項化的時候,就會報錯。

對於抽象方法的使用原則如下:

  • 抽象類必須有子類。即:每一個抽象類一定要被子類所繼承
  • 抽象類的子類(子類不是抽象類)必須要覆寫抽象類之中的全部抽象方法(強制子類覆寫 )
  • 抽象類的物件例項化需要依靠子類完成,採用向上轉型的方法處理

TestDemo.java

abstract class A{	// 定義一個抽象類
	
	public void fun() {		// 普通方法
		System.out.println("A類中---這是一個普通方法");
	}
	
	// 此方法沒有方法宣告,並且使用 abstract 關鍵字,表示抽象類
public abstract void print(); } // 一個子類只能繼承一個抽象類,屬於單繼承侷限 // B 類時抽象類的子類,並且是一個普通抽象類 class B extends A{ public void fun() { System.out.println("B類中---這是一個普通方法 func()"); } // 此處時候需要覆寫 A 類中的抽象方法,並且是強制覆寫 @Override public void print() { // TODO Auto-generated method stub System.out.println("B類中---這是繼承抽象類方法 print()"); } } public class TestDemo { public static void main(String[] args) { A a = new B(); a.print(); a.fun(); } }

控制檯輸出

B類中---這是繼承抽象類方法 print()
B類中---這是一個普通方法 func()

從上面的程式碼,可以總結出:

  1. 抽象類繼承子類裡面會有明確的方法覆寫要求,而普通類沒有
  2. 抽象類只是比普通類多了一些抽象方法的定義,其他組成部分與普通類完全一樣
  3. 普通類物件可以例項化,但是抽象類的物件必須經過向上轉型之後才能例項化物件使用

抽象類的相關限制

抽象類的組成和普通類的區別不大,但是在使用和定義上面會有所區別,所以以下幾點也很重要

  1. 抽象類也存在構造方法。抽象類裡面由於會存在一些屬性,那麼在抽象類中一定會存在構造方法。目的:為屬性初始化。並且子類物件在例項化的時候依然滿足於先執行父類構造,再執行子類構造。
  2. 抽象類是不能被 final 宣告。因為 final 宣告的類是不能有子類的,但是抽象類是必須依靠子類向上轉型才能例項化物件。
  3. 外部抽象類不能被 static 宣告,而內部的抽象類允許使用 static 宣告。使用 static 宣告的內部抽象類就相當於一個外部抽象類,繼承的時候使用“外部類.內部類”的形式表示類名稱
  4. 抽象類中可以使用 static 關鍵字宣告方法。

使用 static 關鍵字宣告內部的抽象類

abstract class A{   // 定義一個抽象類

    // 使用 static 關鍵字定義一個內部抽象類
    static abstract class B{
        public abstract void print();
    }
}

class X extends A.B{

    // 覆寫 B類中的 print方法,這裡是強制覆寫
    @Override
    public void print() {
        System.out.println("*********");
    }
}

public class TestDemo {

    public static void main(String[] args) {
        // 通過內部類的方式來實現
        A.B ab = new X();
        ab.print(); // 輸出:*********
    }
}

使用 static 關鍵字宣告抽象類中的方法

abstract class A{   // 定義一個抽象類
    // 在抽象類中定義一個 static 方法
    public static void print(){
        System.out.println("===============");
    }
}

public class TestDemo {
    public static void main(String[] args) {
        // 直接呼叫我們的抽象類中 static 方法
        A.print();  // 輸出:===============
    }
}

特殊的設計模式

在系統類庫中經常會見到以下這種設計模式。目的:為使用者隱藏不需要知道的子類。

abstract class A {   // 定義一個抽象類

    public abstract void print();   // 抽象方法

    // 定義個私有的類來繼承 A
    private static class B extends A {
        // 根據抽象類的語法,這裡需要強制覆寫 A 中的 抽象方法
        @Override
        public void print() {
            System.out.println("這個是內部子類");
        }
    }

    // 這個方法不受例項化物件的控制
    public static A getInstance(){
        return new B();
    }
}

public class TestDemo {
    public static void main(String[] args) {
        // 此時取得抽象類物件的時候,完全不需要知道 B的存在
        A a = A.getInstance();
        a.print();

        //  A.getInstance().print();    和上面的類似
    }
}

通過一個複雜的程式碼類理解

TestDemo.java

abstract class A{	// 定義一個抽象類
	// 父類構造
	public A() {	// 2.由於 B 是繼承於A,所以先執行A類的構造
		this.print();       // 3.呼叫 A類中 print 方法,但是由於A 的print方法是抽象方法,所以執行子類 B類中的 print 方法
	}
	public abstract void print();	
}

// 一個子類只能繼承一個抽象類,屬於單繼承侷限
// B 類時抽象類的子類,並且是一個普通抽象類
class B extends A{
	
	private int num = 100;
	
	public B(int num) {     // 5.執行完成了 A類的構造方法,就輪到執行 B中的構造方法了,此時的 num的值為 30
		this.num = num; 
	}

	@Override
	public void print() {
		System.out.println("num="+num);     // 4.由於執行當前方法的時候,並沒有例項化出 B,並且由於 num 是int 型別,所以在列印的時候會打印出 int 型別的預設值為 0
	}
}

public class TestDemo {
	public static void main(String[] args) {
		new B(30);      // 1.執行構造方法
		
		// new(30).print() // 這個時候就會輸出30
	}
}