抽象類
在介紹抽象類之前,我們先來看一段代碼:
class Animal{
int age;
String name;
Animal(){} //Animal的構造函數
public void eatFood(){} //每個動物都有喫的食物
public void speaking(){} //每個動物都有它叫的聲音
public void sleep(){ //每個動物都會睡覺,大多數都是閉眼睡覺
System.out.println("閉眼");
}
}
class Dog extends Animal{ //實現一個dog類繼承Animal類
//實現父類Animal中eat()函數
public void eat(){//既是實現,也是重寫
name="旺財";
System.out.println(name+"喫狗糧");
}
//實現父類Animal中speaking()函數
public void speaking(){
name = "旺財"
System.out.println(name+"汪汪的叫");
}
}
class Cat extends Animal{ //實現一個cat類繼承Animal類
//實現父類Animal中eat()函數
void eat(){
name = "喵喵";
System.out.println("喫貓糧");
}
//實現父類Animal中speaking()函數
public void speaking(){
name = "喵喵"
System.out.println(name+"喵喵的叫");
}
}
我們發現在上面的Animal類中有兩個方法eatFood方法和speaking方法,因爲每個動物喫的食物和叫聲是不一樣的,所以他的函數具體是要由繼承它的子類來實現,因此在父類中沒有具體的方法體,但是還是會有方法體就是用{}括起來的部分,爲了解決特殊情況,Java中使用抽象類來封裝沒有具體方法體的方法,
抽象類用關鍵字“abstract”修飾,即" abstract class 類名{ } ",其中抽象類中,我們可以將沒有具體方法體的方法也定義成抽象的,如上面的eatFood方法和speaking方法我們可以這樣定義:
public abstract void eatFood(); //每個動物都有喫的食物,不確定具體的方法體定義成抽象的方法體
public abstract void speaking(); //每個動物都有它叫的聲音,不確定具體的方法體定義成抽象的方法體
由上面的代碼我們可以看出,定義成抽象的方法是沒有函數體的,就連{ }都省略了,這就是抽象方法的一個特點。雖然叫抽象類,其實與我們的普通的類就是多了一個抽象函數而已,其他普通類該有的方法,抽象類同樣的都有,所以:抽象類中不一定有抽象方法,但有抽象方法的類一定是抽象類,且抽象類也可繼承其他的普通類。
抽象類是不能被創建對象的,因爲它可能存在不具體的方法,調用無意義,所以不會讓它去創建對象,但是卻存在構造方法,原因是抽象類是可以被繼承的,只用作父類存在,繼承它的子類在創建對象時,作爲父類的抽象類要調用構造函數爲子類對象中繼承來的成員變量進行初始化,所有這就是構造方法的作用。
當然我們說抽象方法是沒有具體的方法體的,只能存在於抽象類中,那繼承抽象類的子類如何處理這些抽象方法呢?這裏提供兩種方法:一是子類是普通類,繼承抽象類後要重寫抽象類中的抽象函數;二是子類也定義爲抽象類,這樣繼承而來的抽象函數就不用具體實現,由下一個普通類繼承重寫。
既然抽象類是要被繼承才能發揮類的作用,因此抽象類不能與以下幾個關鍵字共存:①final,用該關鍵字修飾的類表示該類不能被繼承;②private,被此關鍵字修飾,子類繼承不到該函數或者類;③ static,不能創建對象,調用沒意思
接口
前面我們介紹了抽象類,發現普通類中存在抽象函數,因此定義成抽象類,那麼如果發現一個抽象類中全都是抽象函數,此時我們可以將該抽象類定義成一個接口,用關鍵字 " interface "修飾,即:interface 接口名{ 抽象函數和靜態常量屬性}。
接口是抽象類的另外一種表現形式,本質上是從抽象類演變過來的,其中在接口當中:屬性默認 public static final;函數默認 public abstract;與抽象類不同之處在於,抽象類表示的還是類 有繼承關係,接口表示的則不是類,那麼意味着接口是不能創建對象的,類與接口之間實現關係,而接口是不能繼承類的,但是接口可以繼承接口且還可以多繼承,原因是接口當中的函數沒有具體的實現,不會像繼承那樣產生調用歧義,具體方法由子類去實現。具體表現形式:
interface A{ } //接口用interface修飾
interface B{ }interface C extends B,A{ } //接口之間可以多繼承
class D implements A { } //類與接口是實現的關係
接口與抽象類的作用
抽象類適用於一個類中部分方法需要靠子類去實現,但是還存在一些方法是所有子類都有的具體行爲;
接口則是對類的功能進行拓展同時也作爲傳遞的中間者,接口的存在向外界提供了統一的接入規範,
我們來看兩個實例:
class Demo04{
public static void main(String[] args){
金毛 s=new 金毛();
s.導盲();
拉布拉多 l=new 拉布拉多();
l.緝毒();
黑背 h=new 黑背();
h.緝毒();
h.導盲();
}
}
abstract class Animal{ //定義一個動物的抽象類
public int age; //動物都存在年齡的屬性
public int name; //動物都存在名字的屬性
public abstract void eat(); //動物都存在喫它相應的食物的方法,是抽象的,具體由子類實現
public abstract void speak(); //動物都存在相應的叫聲方法,是抽象的,具體由子類實現
public void sleep(){ //絕大多數動物都是閉眼睡覺的,這是共有方法
System.out.println("閉眼睡覺...");
}
}
class Dog extends Animal{ //定義一個狗的類繼承動物類
public void eat(){ //具體實現的抽象方法,所有狗肯定會喫狗糧
System.out.println("狗喫狗糧...");
}
public void speak(){ //所有狗也會汪汪的叫
System.out.println("汪汪汪...");
}
}
interface 緝毒功能{ //狗會緝毒但不是所有狗都會緝毒
public abstract void 緝毒(); //具體怎麼緝毒也是具體的狗實現的方法
}
class 拉布拉多 extends Dog implements 緝毒功能{ //定義一個拉布拉多狗的類它有狗的共有屬性因此繼承了Dog類,它會緝毒也實現了緝毒的功能
public void 緝毒(){ //拉布拉多具體的緝毒方法
System.out.println("拉布拉多在緝毒...");
}
}
interface 導盲功能{ //同樣狗會導盲但不是所有狗都會導盲
void 導盲(); //具體怎麼導盲也是具體的狗實現的方法
}
class 金毛 extends Dog implements 導盲功能{ //定義一個金毛的類它有狗的共有屬性因此繼承了Dog類,它會導盲也實現了導盲的功能
public void 導盲(){ //金毛具體的導盲方法
System.out.println("金毛在導盲...");
}
}
class 黑背 extends Dog implements 緝毒功能,導盲功能{ //定義一個黑背的類它有狗的共有屬性因此繼承了Dog類,它會導盲和緝毒,同時實現了導盲和緝毒的功能
public void 緝毒(){
System.out.println("黑背在緝毒...");
}
public void 導盲(){
System.out.println("黑背在導盲...");
}
}
class Bird extends Animal{ //鳥也是動物
public void eat(){ //鳥喫的是蟲子
System.out.println("鳥喫蟲子...");
}
public void speak(){ //鳥的叫聲
System.out.println("嘰嘰喳...");
}
}
class Demo07{
public static void main(String[] args){
Mouse mouse=new Mouse(); //創建一個鼠標對象
KeyBoard keyboard=new KeyBoard(); //創建一個鍵盤對象
Computer com=new Computer(); //創建一個電腦對象
com.getConnect(mouse); //鏈接USB接口將鼠標對象和鍵盤隊形分別傳入,相當於接口上分別插入了鍵盤和鼠標對象
com.getConnect(keyboard);
}
}
class Computer{ //定義一個電腦的類
//獲取 符合USB規範的設備 的連接
//USB device=new Mouse();
//這裏USB device只是定義一個USB接口的引用,並沒有創建對象,創建對象的是實現接口的子類,這裏就是多態的體現
public void getConnect(USB device){ //每個電腦都有一個use的接口,我們需要獲得另一個use的插入對象
device.doSomething(); //然後用獲得的插入對象去對電腦進行操作
}
}
interface USB{ //這是一個use的接口
public void doSomething(); //接口具體做的事是由具體插入對象實現的
}
class Mouse implements USB{ //定義一個鼠標類實現插入的接口
public void doSomething(){ //鼠標有它相應的操作
System.out.println("鼠標連接,開始使用鼠標...");
}
}
class KeyBoard implements USB{ //定義一個鍵盤類實現插入的接口
public void doSomething(){ //鍵盤有它相應的操作
System.out.println("鍵盤連接,開始使用鍵盤...");
}
}
class Demo08{
public static void main(String[] args){
Button b1=new Button(); //按鈕的對象——登錄.........
b1.setAction(new LoginAction()); //將具體的按鈕對象傳進按鈕中
b1.click(); //點擊該按鈕實現相應的動作
Button b2=new Button();//註冊........
//匿名實現子類的匿名對象
b2.setAction(new ButtonAction(){ //這裏創建了一個按鈕動作接口的對象,顯然是無法創建的,也沒有他相應的子類,其實這裏就已經創建了一個類去實現了接口,只是我們不知道這個類叫啥,然後調用父類的構造函數,創建子類對象,實現接口中沒有具體實現的方法
public void doSomething(){
System.out.println("開始註冊");
}
}); //注意這是寫在括號裏面的一段代碼,上面的登錄一樣可以這樣寫
b2.click();
Button b3=new Button();
b3.click();
}
}
interface ButtonAction{ //按鈕動作接口,具體動作由子類實現
public void doSomething();
}
class LoginAction implements ButtonAction{ //登錄按鈕實現按鈕動作接口
public void doSomething(){ //點擊登錄登錄按鈕,進入登錄界面
System.out.println("開始登錄");
}
}
class Button{
private ButtonAction ba;
//將按鈕要做的事情傳遞進來
//ButtonAction ba=new LoginAction();
public void setAction(ButtonAction ba){
this.ba=ba; //將傳進來的按鈕動作接口引用給當前按鈕動作接口引用
}
//當點擊時需要做事情
public void click(){
if(ba==null){ //如果沒有按鈕傳遞進來,相當於什麼都沒做
System.out.println("啥也沒幹");
return;
}
ba.doSomething(); //有按鈕傳遞進來,就做該按鈕相應的事情
}
}