抽象類和接口以及它們的區別

抽象類與接口

##本博客講述了抽象類和接口以及它們的區別。每一個知識點之後都有相應的代碼演示。歡迎大家進行補充##

1. 抽象類

在Java中所有的對象都是通過類來描繪的,但是,並不是所有的類都是用來描繪對象的,
如果一個類中沒有包含足夠的信息來描繪一個具體的對象,這樣的類就是抽象類。

當發現多個類中有共有的方法時,可以將他們抽象出來,例如,狗和狼都會叫這一行爲,而且它們都
屬於犬科類,所以將這一行爲抽象出來,定義犬科爲抽象類。狗和狼均繼承犬科類,並覆蓋其方法。
在子類中具體實現。

具體實現代碼1:

package 抽象類;
abstract class 犬科{
	abstract void 叫();//抽象函數,需要用abstract修飾,用分號結束。
}
class Dog extends 犬科{
	void 叫(){
		System.out.println("汪汪汪 ");
	}
}

class Wolf extends 犬科{
	void 叫(){
		System.out.println("吼吼吼");
	}
}

public class AbstractDemo1 {
public static void main(String[] args) {
	Dog dog = new Dog();
	dog.叫();
	Wolf wolf = new Wolf();
	wolf.叫();
}
}

具體實現2:

`public abstract class Animal {
  	public abstract void cry();
}

public class Cat extends Animal{
@Override
public void cry() {
    System.out.println("貓叫:喵喵...");
	 }
}

public class Dog extends Animal{

@Override
public void cry() {
    System.out.println("狗叫:汪汪...");
}
}

public class Test {
 public static void main(String[] args) {
    Animal a1 = new Cat();
    Animal a2 = new Dog()
    a1.cry();
    a2.cry();
}
}`

注意:

1. 抽象類和抽象方法必須由abstract關鍵字指定。抽象方法一定要定義在抽象類中。
2. 抽象類不可以創建實例(即不能new對象)
		原因:調用抽象方法沒有意義。所以抽象類必須被繼承。
3. 只有覆蓋了抽象類中所有的抽象方法後,其子類纔可以實例化。否則該子類還是一個抽象類。
4. 任何子類必須重寫父類中的所有抽象方法,否則聲明自身爲抽象類。

細節:

1.抽象類一定是一個父類?
	是的,因爲抽象類是不斷抽取而來的。
2.抽象類是否有構造方法?
	有,雖然抽象類不能給自己的對象初始化,但是可以給自己的子類對象初始化,
3.抽象類和一般類的異同點:
	相同:
		1.都是用來描述事物的。
		2.它們之中都可以定義屬性和行爲。
	不同:
		1.一般類可以具體的描述事物;抽象類描述事物的信息不具體。
		2.抽象類中可以多定義一個成員:抽象函數。
		3.一般類可以創建對象,而抽象類不能創建對象。
3.抽象類中是否可以不定義抽象方法?
	可以的,此時的意義僅僅是不讓該類創建對象。	
4.抽象關鍵字abstract不可以和哪些關鍵字共存?
	1)final 修飾的類不能有子類,而抽象類必須有子類。
	2)private 私有的,也不能被覆蓋
	3)static 靜態方法隨着類的加載而加載。

案例分析:

`package 抽象類;
/*
 *需求:公司中程序員有姓名,工號,薪水,工作內容
 *	項目經理除了有姓名,工號。薪水。還有獎金,工作內容, 
 *
 *分析:
 *	程序員
 *		屬性:姓名 工號 薪水
 *		行爲:工作(code...)
 *  經理: 
 *  	屬性: 姓名 工號 薪水 獎金
 *   	行爲: 工作(manage...)
 *   
 * 所以 抽象類爲員工Employee
 *  
 */
//員工抽象類
abstract class Employee{
private String name;
private int id;
private double pay;
public Employee(String name,int id,double pay){
	this.name = name;
	this.id = id;
	this.pay = pay;
}

@Override
public String toString() {
	return "Employee [name=" + name + ", id=" + id + ", pay=" + pay + "]";
}

abstract void work();
}
//程序員
class Programmer extends Employee{

public Programmer(String name, int id, double pay) {
	super(name, id, pay);//調用父類的構造方法
}
void work(){
	System.out.println("code....");
}

}

class Manager extends Employee{
  	private double award;
	public Manager(String name, int id, double pay,double award) {
	super(name, id, pay);
	this.award = award;
}

void work(){
	System.out.println("manage...");
}
}

public class AbstractDemo2 {
public static void main(String[] args) {
	Programmer programmer = new Programmer("小曾", 2, 10000);
	System.out.println(programmer);
	programmer.work();
}
}`

2. 接口

當一個抽象類中的方法全是抽象的時候,此時用另一種特殊的形式體現。用interface關鍵字定義
接口是用來建立類與類之間的協議,它所提供的只是一種形式,而沒有具體的實現。
接口是抽象類的延伸
接口是隱式抽象的,當聲明一個接口的時候,不必使用abstract關鍵字。
接口中每一個方法也是隱式抽象的,聲明時同樣不需要abstract關鍵字。
interface Animal {
	public void eat();
	public void travel();
}

接口的特點

1.接口無法被實例化,但是可以被實現。一個實現接口的類,必須實現接口內所描述的所有方法,否則就必須聲明爲抽象類
2.子類必須覆蓋接口中所有的抽象方法後,子類纔可以實例化。
3.接口中不存在具體的實現的方法
4.接口沒有構造方法。
5.接口中所有的方法必須是抽象方法。
6.變量必須有固定的修飾符修飾,public static final 所以接口中的變量也稱爲常量
7.方法必須有固定的修飾符,public abstract ,所以接口中的成員都是公共的。
8.接口支持多繼承。
具體代碼1:
`package 接口;

/*
 * 定義一個接口,接口中可以有成員變量和方法
 * 注意:
 * 	變量:變量必須有固定的修飾符修飾,public static final 所以接口中的變量也稱爲常量
 *  方法:方法必須有固定的修飾符,public abstract ,所以接口中的成員都是公共的。
 */
interface Demo{
public static final int NUM = 6;
public abstract void show1();
public abstract void show2();

/*
 * 也可以寫成此類型
 * int NUM = 6;
 * void show1();
 * void show2();
 */
}

//類實現接口,並重寫接口中的方法
public class DemoImpl implements Demo{
	@Override
public void show1() {
	
}
@Override
public void show2() {
	
}

}`
具體代碼2:
class D{
	public void show(){};
interface A{
	void show();
}
interface B{
	void show();
}
class C extends D implements A,B{
	public void show(){
	}
}
接口的好處:
接口中的方法都沒有方法體,由子類來明確。接口可以多實現。
接口的出現避免了單繼承的侷限性;
父類中定義的事物的基本功能;接口中定義事物的擴展功能。
接口與接口是多繼承
在Java中,類的多繼承是不合法,但接口允許多繼承。
在接口的多繼承中extends關鍵字只需要使用一次,在其後跟着繼承接口。 
代碼演示
interface interA{
	void show1();
}
interface interAA{
	void show11();
}
interface interB extends interA,interAA{//接口實現多繼承
	void show2();
}

class Test implements interB{

@Override
public void show1() {}

@Override
public void show11() {}

@Override
public void show2() {}
}

沒有抽象方法的抽象類:抽象類中可以不定義抽象方法,原因僅是不讓該類創建對象。

代碼過程:
1.定義接口Inter(其中有四個抽象方法),類InterImpl1,InterImpl2 分別實現Inter接口,

`interface Inter{
//定義四種顯示功能
public void show1();
public void show2();
public void show3();
public void show4();
}

//定義一個類,要使用顯示第一種顯示方法
class InterImpl1 implements Inter{

@Override
public void show1() {
	System.out.println("顯示第一種方式");
}
//爲了讓該類實例化,還需要覆蓋其他三個方法,
public void show2(){}
public void show3(){}
public void show4(){}
}
class InterImpl2 implements Inter{
@Override
public void show3() {
	System.out.println("顯示第三種方式");
}
//爲了讓該類實例化,還需要覆蓋其他三個方法,
public void show2(){}
public void show1(){}
public void show4(){}
}

爲了使用接口中的部分方法,而覆蓋了全部的方法,而且每一個子類都要這麼做,複用性差。
所以
將這些不同的方法都單獨抽取到一個獨立的類中,讓這個類去實現接口,並覆蓋接口中所有的方法。

`abstract class InterDemoImpl implements Inter{   
//重寫接口中所有的方法
@Override
public void show1() {
}

@Override
public void show2() {
}

@Override
public void show3() {
	
}

@Override
public void show4() {
}

}`

class InterImpl1 extends InterDemoImpl{
public void show1(){
	System.out.println("顯示第一個方法");
}
}	

class InterImpl2 extends InterDemoImpl{
public void show3(){
	System.out.println("顯示第三個方法");
}
}


public class DemoImpll1 {
public static void main(String[] args) {
 InterImpl1 impl1 = new InterImpl1();
 impl1.show1();
 InterImpl2 impl2 = new InterImpl2();
 impl2.show3();
}
}
這個類並不知道具體的實現內容,都是空實現,不需要將此類創建對象,所以對其抽象化。

接口的設計思想

1.接口的出現對功能實現了擴展。
2.接口的出現定義了規則
3.接口的出現降低了耦合性。

接口和抽象類的區別

事件描述:
犬:假如按照功能分類:導盲犬,緝毒犬。。。
行爲:
吼叫();
吃飯();

abstract class 犬{
public abstract void 吼叫();
public abstract void 吃飯();
}



abstract class 緝毒{

public abstract void 緝毒();
}

class 緝毒犬 extends 犬{

@Override
public void 吼叫() {
}
@Override
public void 吃飯() {
}
public void 緝毒(){
	
}
}
//其他的動物可能也會有緝毒功能,無法實現多繼承,當犬是接口,緝毒也是接口時,可以多實現。但是類負責描述的是事物的基本功能,接口負責描述事物的擴展功能。所以,犬可以描述爲類,緝毒可以描述爲接口。
 	
所以 以上代碼改爲:
abstract class 犬{
	public abstract void 吼叫();
	public abstract void 吃飯();
}

interface  緝毒{
	public abstract void 緝毒();
}
class 緝毒犬 extends 犬  implements 緝毒{
@Override
public void 吼叫() { }
@Override
public void 吃飯() { }
public void 緝毒(){ }
}

抽象類與接口的區別:

1.抽象類是描述事物的基本功能,可以定義非抽象的方法;接口中的定義的方法是抽象的。
2.類與類之間是繼承關係,類與接口是實現關係。
3.抽象類中的方法可以有方法體,就是能實現方法的具體功能,但是接口中的方法不行。
4.抽象類中的成員變量可以是各種類型的,而接口中的成員變量只能是 public static final 類型的。
5.接口中不能含有靜態代碼塊以及靜態方法(用 static 修飾的方法),而抽象類是可以有靜態代碼塊和靜態方法。
6.一個類只能繼承一個抽象類,而一個類卻可以實現多個接口。

擴展

對於抽象類而言,它是自下而上來設計的,我們要先知道子類才能抽象出父類,而接口則不同,它根
本就不需要知道子類的存在,只需要定義一個規則即可,至於什麼子類、什麼時候怎麼實現它一概不
知。比如我們只有一個貓類在這裏,如果你這是就抽象成一個動物類,是不是設計有點兒過度?我們
起碼要有兩個動物類,貓、狗在這裏,我們在抽象他們的共同點形成動物抽象類吧!所以說抽象類往
往都是通過重構而來的!但是接口就不同,比如說飛,我們根本就不知道會有什麼東西來實現這個飛
接口,怎麼實現也不得而知,我們要做的就是事前定義好飛的行爲接口。所以說抽象類是自底向上抽
象而來的,接口是自頂向下設計出來的。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章