Java抽象類和接口的區別及聯系


抽象類

注:先將抽象類中的兩種方法解釋完,再綜合解釋抽象類

抽象方法

  • 應用場景:其下所有子類都應該有該方法但是大部分子類具體的執行步驟是有所不同的。
  • 必須重寫:也可以說“必須實現”,因為父類的抽象方法沒有方法體。
  • 關鍵字:abstract

普通方法

  • 應用場景:其下所有子類都應該有該方法而且大部分子類具體的執行步驟是完全相同。
  • 可重寫:普通方法是可以重寫的,對於每一個子類執行步驟都是相同的自然沒有必要去重寫;絕大部分子類執行步驟相同的情況就要在那一小部分不同的子類中去重寫。
  • 選擇依據:見應用場景

抽象類詳解

  • 定義:其中有抽象方法的類都必須定義為抽象類。
  • 存在意義:實現程序的多態性。(必須被繼承,否則它的存在是沒有意義的)

問題:既然普通方法可以被重寫,那么子類中有不同執行步驟我再重寫就好了為什么我還需要抽象方法呢?

答:抽象方法是必須被重寫且父類中沒有方法體,而普通方法不是必須被重寫而且父類中有方法體;這樣就造成一個問題:程序過大而不使用這種方法,父類中普通方法太多,子類都要記得去重寫,但是java虛擬機又不會告訴你去重寫,不重寫子類就按照父類默認的方法體執行了;而抽象方法就不同了,子類不重寫java虛擬機報錯,這時候就起到了提醒以及強制的作用。

接口

  • 定義:接口的存在是為了實現程序的可擴展性。
  • 存在意義:如果你的類的結構體系中,某一個類要擴充功能怎么辦?那么我們就要去修改這個類的父類甚至說是超類嗎?這顯然不合理。(而且如果你使用別人提供的類,根本就不可能去修改它)也許你要一直追溯到Object都不行。可是使用接口,你想給這個體系中的某個類擴充功能,只需要給這個類實現一個新的接口,自然就會提供新的功能,絲毫不會影響它的超類, 而它的子類自動也擴充了它新增加的這個接口的方法(有點象C++多繼承)。這使的軟件的功能擴展變得更容易。設計模式中有一條開閉原則,說:軟件實體必須都修改關閉,對擴展開放。 使用接口,就可以滿足這樣的設計要求。
  • 應用場景:該類下某些子類需要該方法而有一些則不需要,那么就在需要的子類下接入接口即可。

問題:既然接口是某一子類特有的,那么為什么我們不在該子類下直接定義普通方法呢?

答:這是沒有大程序編寫經驗的常見問題。所謂的接口,就是使用的人不知道你的子類是什么,而調用你的子類。這個時候別人怎么知道你的子類有什么方法呢?於是你告訴他,我的子類是繼承了某個接口的,別人一看,哦,這個接口里有方法a、b、c,這樣就可以調用了。你說為啥不直接告訴他你的子類呢,這個就是復用性了。一個接口,你可以用多個子類去實現它,別人只要調用一個接口,通過換子類,就能在不改代碼的情況下使用多種功能。當然,子類自然去實現這些方法也行啊,但如果你做了一個父類,人家不明白你的意思,繼承你的父類, 忘記了寫要實現的方法怎么辦?接口起到了強制性的措施。

注:抽象類和接口共同支持了程序的可維護性。

區別以及聯系

區別

  • 抽象類中可以有構造方法,接口中沒有。
  • 抽象類中可以包含非抽象的普通方法,接口中的所有方法必須都是抽象的,不能有非抽象的普通方法。
  • 抽象類中可以有普通成員變量,接口中沒有普通成員變量。
  • 抽象類中可以包含靜態方法,接口中不能包含靜態方法。
  • 抽象類中的抽象方法的訪問類型可以是 public,protected ,但接口中的抽象方法只能是 public 類型的,並且默認即為 public abstract 類型。
  • 一個類可以實現多個接口,但只能繼承一個抽象類。
  • 抽象類和接口中都可以包含靜態成員變量,抽象類中的靜態成員變量的訪問類型可以任意,但接口中定義的變量只是public static final 類型,並且默認即為 public static final 類型。

聯系

  • 都提高了代碼的復用性。
  • 都提高了代碼的可維護性以及可擴展性。
  • 都體現了面向對象編程的多態性。
  • 接口是一個特殊的抽象類。

本質區別

抽象類是對事物本質的抽象,而接口是對某幾種行為的耦合手段。

通過實例理解

首先我們梳理一下類之間的關系(標注了*了的為抽象類)

  • Student*(學生)
    • Studystudent*(學習類)
      • Libstudent(文科生)
      • Sciencestudent(理科生)
    • Longhairstudent*(藝術類)
      • Artstudent(美術生)
      • Musicstudent(音樂生)

然后梳理各種學生的行為特征(標注了*的為抽象方法,標注了#的為接口)

  • Student的特征:起床,吃飯,學習*,睡覺
    • Studystudent新加的特征:考試*
      • Libstudent新加的特征:多做語文#
      • Sciencestudent新加的特征:多做數學#
    • Longhairstudent新加的特征:技能訓練*

接下來上代碼

//Student

public abstract class Student {
	public void getup() {//起床,所有學生都要做且步驟相同
		System.out.println("起床");
	}
	public void eat() {
		System.out.println("吃飯");
	}
	public void sleep() {
		System.out.println("睡覺");
	}
	abstract public void study();
}

//Studystudent

public abstract class Studystudent extends Student {
	abstract public void exam();
}
//Longhairstudent

public abstract class Longhairstudent extends Student {
	abstract public void skilltrain();
}
//Libstudent

public class Libtstudent extends Studystudent implements Morechinese{

	@Override
	public void dochinese() {
		System.out.println("多做語文");
	}

	@Override
	public void exam() { 
		System.out.println("考試政史地");
	}

	@Override
	public void study() {
		System.out.println("學習政史地");
	}

}
//Sciencestudent

public class Libtstudent extends Studystudent implements Morechinese{

	@Override
	public void dochinese() {
		System.out.println("多做語文");
	}

	@Override
	public void exam() { 
		System.out.println("考試理化生");
	}

	@Override
	public void study() {
		System.out.println("學習理化生");
	}

}
//Artstudent

public class Artstudent extends Longhairstudent{

	@Override
	public void skilltrain() {
		System.out.println("美術技能訓練");
	}

	@Override
	public void study() {
		System.out.println("學習畫畫基本功");
	}

}
//Musicstudent


public class Musicstudent extends Longhairstudent{

	@Override
	public void skilltrain() {
		System.out.println("唱歌技能訓練");
	}

	@Override
	public void study() {
		System.out.println("學習唱歌基本功");
	}

}
//主類

public class Demo {
	public static void Oneday(Student cuteStudent) {
		cuteStudent.getup();
		cuteStudent.eat();
		cuteStudent.study();
		cuteStudent.sleep();
	}

	public static void main(String[] args) {
		Oneday(new Artstudent());
	}
}

我們在主類中定義了一個方法體(Oneday),用來查看一個學生的一天大體的活動。該方法的形參是Student的引用,那么我們只需要在用這個方法的時候改變實例化即可得到不同類型學生的一天。

執行結果如下圖:

如果改成new Libstudents,執行結果如下圖:

那么我們定義了接口該如何使用呢?在主類中加入如下代碼:

Moremath iMoremath=new Sciencestudent();
iMoremath.domath();

或者;

new Sciencestudent().domath();

執行后會顯示“多做數學”。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM