相關文章:java
本文來介紹Java的抽象類和接口的使用。ide
在前面的文章中提到過:父類比子類更加抽象,子類比父類更加具體。this
在《一文打盡Java繼承的相關問題》這篇文章中舉了動物和狗的例子:3d
public class Animal { private String name; private int age; public Animal(String name, int age) { this.name = name; this.age = age; } public Animal() { } public void say() { System.out.println("我是" + name + ",今年" + age + "歲了"); } //getters and setters ... }
public class Dog extends Animal { private String address; public Dog(String name, int age, String address) { super(name, age); this.address = address; } public Dog() { } public void say() { System.out.println("我叫" + super.getName() + ",今年" + super.getAge() + "歲了,家住" + address + ",汪汪汪..."); } public void watchDoor() { System.out.println("我在" + address +"看門..."); } //getters and setters ... }
上面Dog
類很天然地繼承了Animal
類,沒毛病!可是仔細琢磨一下Animal
類的say()
方法。code
動物是一個很寬泛的概念,若是寫代碼表示,咱們日常見到的大部分生物均可以繼承該類。以下圖:對象
有這麼多類繼承Animal
類,那Animal
類的say()
方法這樣寫合適嗎?由於每種動物說話的方式都不一樣,而動物又是這麼寬泛的一個概念,咱們一般會new Dog()
或new People()
,但不多會去new Animal()
。blog
因此Animal
類的say()
方法體對其來講就是雞肋通常的存在,由於即便有方法體,也會被其子類重寫。既然這樣那就乾脆不要方法體了。繼承
換句話說,咱們將Animal
類再進行更高層次地抽象,它具備各類動物都有的屬性,好比name
、age
,也有各類動物都有的行爲,好比say
。可是,Animal
類並不具體實現該方法,具體的實現交給子類來作。接口
這樣一來,誰繼承了Animal
類,誰就有了它的屬性和行爲,子類不用管父類的行爲是否合適,由於父類的行爲「有名無實」,因此子類只需繼承這些「名」,具體的「實」則由子類來完成。開發
這樣的Animal
類就是抽象類。
下面將上例中的Animal
類修改成抽象類,Dog
類無需改動:
public abstract class Animal { private String name; private int age; public Animal(String name, int age) {//有參構造器 this.name = name; this.age = age; } public Animal() {//無參構造器 } public abstract void say();//抽象方法 public String getName() {//被具體實現的方法 return name; } public void setName(String name) { this.name = name; } //getters and setters.. }
下面是抽象類的特色:
(一)抽象類被abstract
關鍵字修飾。
public abstract class Animal { //...... }
(二)類中沒有方法體的方法叫抽象方法,也須要使用abstract
關鍵字修飾。
public abstract void say();//抽象方法
(三)有抽象方法的類必定是抽象類。
(四)沒有抽象方法的類也能夠是抽象類。
(五)抽象類中能夠有成員變量、構造器、被具體實現的方法。構造器不能是抽象的。
(六)抽象類不能被實例化,可是能夠聲明一個抽象類變量
Animal animal = new Animal();//報錯: 'Animal' is abstract; cannot be instantiated Anima animal;//抽象類變量,可行
咱們之前遇到的類,好比Dog
類,是用來描述對象的,但抽象類的方法沒有具體實現,因此它沒有足夠的信息來描述對象,因此抽象類只能被繼承用來描述其子類而不能實例化。
(七)子類擴展抽象父類有兩種選擇:
public class Dog extends Animal { //屬性、構造器、其餘方法 //實現抽象父類的抽象方法 @Override public void say() { System.out.println("我叫" + super.getName() + ",今年" + super.getAge() + "歲了,家住" + address + ",汪汪汪..."); } }
public abstract class Dog extends Animal { //屬性、構造器、其餘方法 //能夠選擇不實現父類的抽象方法 }
生活中有一種接口是你們天天都在用的,那就是插座。
不論是什麼樣的電器,冰箱、電視、電腦、電風扇,只要買回來,就能插上通電。之因此這麼便利,就是由於電器生產商和插座生產商都遵照了一個生產規範:我把插座生產成這個模樣,你把插頭也生產成這個模樣,我無論你電器內部是啥樣,你也不用管個人插座內部是啥樣,你們把產品生產好,各自賣給客戶,合做愉快,一塊兒賺錢。這些產品若是之後壞了,那就再買一個遵照規範的就能繼續配套使用了。
想想,若是沒有這個規範,插座和插頭生產的千奇百怪,買回來怎麼用?只能把插座和冰箱拆開,用手接220V的電線了。
換句話說,接口就是生產規範 / 標準,或者雙方遵照的協議,只要雙方都遵照,那麼就能愉快地交流、愉快地合做。
在Java開發中,一個軟件系統確定不是由一我的完成的,而是由一個團隊完成的。那如何避免甲寫的類乙不能用,乙寫的類丙不能用呢,最後致使甲改了乙的代碼,乙改了丙的代碼?事先定好規範(接口),你們都遵照接口,只要我知道你的接口,那麼我不須要知道你的具體代碼,就能調用你的類。
掌握關於接口幾個特色就能愉快地寫接口了:
(一)Java中使用inteface
關鍵字來聲明一個接口,接口必須是public
的,只有公有了才能讓你們遵照:
public interface Runnable { }
(二)接口中一般寫各類抽象方法,但只聲明,不能寫方法體。
public interface Runnable { /*public abstract*/ void run(); }
(三)沒必要將方法聲明爲public abstract
,在接口中的全部方法都默認的是public abstract
修飾。
(四)接口中不能有成員變量、靜態代碼塊。
(五)接口中能夠含有常量,常量默認是public static final
修飾。
public interface Runnable { /*public static final*/ int i = 1; void run(); }
(六)類經過implements
關鍵字實現接口,必須同時實現接口中的全部方法。
public class Dog implements Runnable { @Override public void run() { System.out.println("跑得飛快"); } //...... }
(七)若是實現接口的類是抽象類,能夠不用實現接口中的方法。
(八)一個類能夠同時繼承類和實現接口。
public class Dog extends Animal implements Runnable { //...... }
(九)一個類能夠實現多個接口。
public class Dog implements Runnable, Flyable { //...... }
(十)接口之間能夠繼承,而且容許多繼承。
public interface A { //...... } public interface B extends A, Runnable{ //...... }
(十一)接口不能被實例化,可是能夠聲明一個接口變量。
Runnable runnable = new Runnable();//'Runnable' is abstract; cannot be instantiated Runnable runnable;//接口變量,可行
抽象類用abstract
關鍵字聲明,抽象類中除了能夠有抽象方法(用abstract
關鍵字聲明)外,還能夠有普通類的成員變量、構造器、方法。不能被實例化,但能夠聲明抽象類的變量。子類繼承抽象類要實現父類的抽象方法(若是子類是抽象的,則不用實現)。
接口用interface
關鍵字聲明,接口中只能有抽象方法、常量(忽略修飾符)。不能被實例化,但能夠聲明接口變量。接口之間能夠繼承,且容許多繼承。類實現接口使用implements
關鍵字,且必須實現接口中的抽象方法(若是類是抽象的,則不用實現)。
總結了抽象類和接口的特色,發現抽象類好像也能做爲「接口」使用。那有了抽象類,爲何還要有接口?
類只能單繼承,若是使用抽象類做爲「接口」,這意味着一個類只能遵照一份「接口」,顯然不符合實際。而接口則靈活多了。
若有錯誤,還請指正。