簡述Java中抽象類和介面,及其兩者區別
在說區別之前,先簡要說一下什麼是抽象類和介面
1.抽象類
用abstract修飾的類叫做抽象類。
在講抽象類之前有必要強調一下abstract修飾符:
1.abstract修飾的類為抽象類,此類不能有物件,(無法對此類進行例項化,說白了就是不能new);
2.abstract修飾的方法為抽象方法,此方法不能有方法體(就是什麼內容不能有);
關於抽象類的使用特點:
1.抽象類不能有物件,(不能用new此關鍵字來建立抽象類的物件);
2.有抽象方法的類一定是抽象類,但是抽象類中不一定有抽象方法;
3.抽象類中的抽象方法必須在子類中被重寫。
細心地同學可能會問到:抽象類不能被“new”,抽象方法必須重寫,那麼定義它們做什麼嘞?
答:抽象類生來就註定它是要被繼承的,如果沒有任何一個類去繼承它的話,那麼也就失去了它的意義;抽象方法生來就是要被重寫的,而且是必須重寫。(只要繼承了某個抽象類,就必須去重寫此抽象類中含有的抽象方法)
話不多說,看程式碼:
public abstract class Animal {
public abstract void eat();
public abstract void sleep();
}
以上程式碼是定義了一個叫做animal的抽象類,其中含有eat()和sleep()兩個抽象方法。
這裡指的注意的是:抽象方法不能有方法體,在方法後面加一個大括號而裡面什麼都不寫也是不行的,編譯器會報“abstract methods do not specify a body”這樣一個錯誤。如下:
定義了一個animal類之後再定義一個cat類:
public class Cat extends Animal{ @Override public void eat() { System.out.println("我是貓,我吃的是貓糧呀"); } @Override public void sleep() { System.out.println("我是貓,我比你們人類睡的時間短!"); } }
在這裡指的注意的是:當一個類繼承抽象類的時候,這個類必須去重寫所繼承的抽象類的抽象方法,否則編譯器會報“The type Cat must implement the inherited abstract method Animal.eat()”的錯誤。具體如下:
而,當重寫完相對應的抽象類中的所有抽象方法之後,編譯器也就不再報錯:
此時,我再來寫一個Person類:
public class Person extends Animal {
@Override
public void eat() {
// TODO Auto-generated method stub
System.out.println("我是人,我要吃大魚大肉!!!");
}
@Override
public void sleep() {
// TODO Auto-generated method stub
System.out.println("我是人,每天必須睡夠24個小時!!!!");
}
}
OK,現在類已經寫完了。接下來結合以上的程式碼說一下抽象類的用處:
細心地同學可以看得出,在cat和person這兩個類中都含有了sleep和eat這兩個方法,但是它們的方法體卻不一樣。重點就在這裡,假設不定義animal這個抽象類以用來讓cat和person去繼承的話,雖然也要在cat和person中定義sleep和eat這兩個方法,看似程式碼上沒有太多簡化。但是這背後卻隱藏著一個規範問題:也就是“是不是”的問題。cat和person都“是”animal,所以就必須繼承animal裡面的方法。相當於提供了一個大的體制。就好比人:人活著就必須要遵守國家的法律,而至於你信仰佛,還要遵守“佛法”,你信仰共產黨,你還要遵守黨章和黨紀。那就是你自己的事情了
2.介面
介面就是一個規範和抽象類比較相似。它只管做什麼,不管怎麼做。通俗的講,藉口就是某個事物對外提供的一些功能的宣告,其定義和類比較相似,只不過是通過interface關鍵字來完成
其中重要的幾個知識點:
1.介面中的所有屬性預設為:public static final ****;
2.介面中的所有方法預設為:public abstract ****;
3.介面不再像類一樣用關鍵字 extends去“繼承”,而是用 implements 去“實現”,也就是說類和介面的關係叫做實現,(例如:A類實現了B介面,那麼成為A為B介面的實現類。而類與類之間的繼承的話,叫做A類繼承了B類,其中B類即為A類的父類)。實現介面與類的繼承比較相似
程式設計一事書讀的再多沒用,只會培養出來嘴上懂得怪多,但是屁都敲不出來的鳥人!!動手出真知!!!具體看一下程式碼:
public interface Sleep {
public static int a = 1;
public static int b = 2;
public void ioSleep(int i);
}
public interface Eat {
public abstract void ioEat();
}
public interface Study {
public void ioStudy();
}
public class Cat implements Sleep,Eat{
@Override
public void ioSleep(int i) {
System.out.println("我是貓,我每天都不用睡覺!!!");
}
@Override
public void ioEat() {
System.out.println("我是貓,我吃貓糧!!!");
}
}
public class Person implements Sleep,Eat,Study{
@Override
public void ioStudy() {
System.out.println("我是人,我每天都要學習");
}
@Override
public void ioEat() {
System.out.println("我是人,我要吃大魚大肉還要喝酒");
}
@Override
public void ioSleep(int i) {
System.out.println("我是人,我每天要睡24小時");
}
}
以上程式碼定義了三個介面分別是:Study,Eat,Sleep,以及兩個類分別是Cat和Person。其中Cat類實現了兩個介面分別是:Eat和Sleep,而Person實現了三個介面分別是:Study,Eat,Sleep。這是為什麼呢?就是因為Cat並不需要學習,而Person需要學習,所以在Cat類中沒有實現Study這個介面,而在Person中卻是有的。那麼顯而易見,介面所闡述的是“有沒有”的問題,而剛剛所說的抽象類闡述的是“是不是”的問題
所以也就可以列出抽象類和介面的幾點區別:
1.抽象類描述的是“是不是”的問題,而介面描述的是“有沒有”的問題;
2.在Java中類的繼承是“單繼承”,可以“多對一”,但是不允許“一對多”。而一個類卻可以同時實現多個介面;
關於介面的注意事項:
如果把Cat的程式碼裡面加上“a++"這樣一句程式碼的話,編譯器會報“The final field Sleep.a cannot be assigned”這樣一個錯誤。至於原因就是因為在介面中所有的屬性的修飾符都預設為"public static final",(雖然當時定義a的時候並沒有明確指出要用final修飾)而final所修飾的屬性裡面的常量值是不能做修改的。
以上程式碼報“Abstract methods do not specify a body”的錯誤,因為介面中的方法預設修飾符為“public abstract”