java?抽象類示例詳解
一、抽象類概述:
我們知道,類用來模擬現(xiàn)實事物。一個類可以模擬一類事物,而某個類的一個實例化對象可以模擬某個屬于該類的具體的事物。類中描繪了該類所有對象共同的特性,當一個類中給出的信息足夠全面時,我們就可以實例化該類;比方說,在Dog類中定義了name,age,fur_color,sex等屬性,以及habit,eat等行為時,我們就可以創(chuàng)建一個Dog類對象,來模擬某個具體的Dog,比如你家的寵物狗,或者是神犬小七等。但是,當一個類中給出的信息不夠全面時,(比方說有無法確定的行為),它給出的信息不足以描繪出一個具體的對象,這時我們往往不會實例化該類,這種類就是抽象類。打個比方,對于Animal類,是,所有的動物都有吃喝的行為,定義eat方法可以描述動物“吃”這一行為,但是每種動物吃的都不一樣,因此一個eat方法并不能準確描述吃什么,怎么吃。這時Animal給出的信息就不足夠描述一個對象,我們就不能去實例化Animal類。
在Java中,我們通過在類前添加關(guān)鍵字abstract(抽象的)來定義抽象類。如下所示 :
public abstract class Animal { //Animal類此時就是一個抽象類。 } class Dog extends Animal { //Dog類繼承了Animal類,是Animal類的子類。 }
二、抽象方法 :
1.概述 :
我們將“只有方法聲明,沒有方法體”的一類方法統(tǒng)稱為抽象方法,抽象方法用關(guān)鍵字abstract修飾。需要注意的是,如果一個方法已經(jīng)確定是抽象方法,那么它絕不能再有方法體,即不能出現(xiàn)大括號,而是只需要在()后面添加一個分號即可,否則IDEA會提示報錯信息,如下圖所示 :
還要注意一點,如果某個類中已經(jīng)出現(xiàn)了抽象方法,那這個類必須定義成抽象類,否則會報錯,如下GIF動圖演示——我們刪掉Animal類前的abstract修飾符,IDEA立馬就會給出提示信息,如下 :
也就是說,擁有抽象方法的類一定是抽象類;但是抽象類不一定有抽象方法。
2.應用 :
當父類需要定義一個方法,卻不能明確該方法的具體實現(xiàn)細節(jié)時,可以將該方法定義為abstract,具體實現(xiàn)細節(jié)延遲到子類。(讓子類重寫這個方法)
就比如我們剛才說的——Animal類中的eat() 方法,我們可以先將其定義為抽象方法,然后在子類中,比如說Dog類中重寫eat() 方法,給出對Dog類對象“吃”這一行為的一些具體描述。
up以Animal類,Dog類和Test類為例,代碼如下 :
package knowledge.polymorphism.about_abstract.introduction; public abstract class Animal { /** 父類 */ //將Animal類中的eat() 方法定義為抽象類,具體實現(xiàn)延遲到子類。 public abstract void eat(); } class Dog extends Animal { /** 子類 */ //子類重寫父類的抽象方法,也稱為子類實現(xiàn)了該抽象方法。 public void eat() { System.out.println("狗是雜食性動物,喜食肉類,喂養(yǎng)時應該以動物蛋白為主,素食為輔。"); } } class Test { public static void main(String[] args) { Dog dog = new Dog(); dog.eat(); } }
運行結(jié)果 :
3.特點 :
①若父類中定義了一個抽象方法,要求其所有非抽象子類都必須重寫該抽象方法。否則IDEA會報錯,如下圖所示 :
②前面我們說了,抽象方法用abstract關(guān)鍵字修飾。這里再補充一點——抽象方法不能再使用private,final 或者static關(guān)鍵字來修飾,即abstract不能與private,final或static共同出現(xiàn),這是因為定義抽象方法的目的就是想將方法的具體實現(xiàn)延遲到子類,最終是要被子類重寫的,而private,final,static這幾個關(guān)鍵字都和“方法重寫”的目的背道而馳。
如果你固執(zhí)己見,非要讓abstract和這幾個關(guān)鍵字一同出現(xiàn),IDEA也是毫不客氣,直接報錯,如下圖所示 :
三、抽象類特點 :
1.關(guān)于abstract關(guān)鍵字 :
abstract關(guān)鍵字只能用于修飾類和方法,用于聲明抽象類和抽象方法。其中,抽象類必須使用abstract關(guān)鍵字修飾。聲明時格式如下 :
訪問權(quán)限修飾符 abstract class 類名{ // }
訪問權(quán)限修飾符 abstract 返回值類型 方法名(形參列表);
舉個例子,如下 :
//抽象類 public abstract class Animal { //抽象方法 public abstract void eat(); //抽象方法最后加一個分號即可,不可以有大括號。 }
2.抽象類不能被實例化,只能創(chuàng)建其子類對象 :
即,我們不能創(chuàng)建抽象類對象(這里的對象指的是堆空間中真正的對象,即不能“new 抽象類”),原因我們在開篇抽象類的概述中也提到了,這里不再贅述。如果你頭鐵,非要創(chuàng)建抽象類對象,IDEA也不是吃素的,直接報錯,如下圖所示 :
當然,如果抽象類的子類沒有用abstract關(guān)鍵字修飾,那么我們可以創(chuàng)建其子類對象,如下圖所示 :
3.抽象類子類的兩個選擇 :
如果某個類繼承了一個抽象類,那么這個類有兩個選擇——要么實現(xiàn)父類所有的抽象方法,要么子類本身也定義成抽象類。當然,肯定也不會是瞎jb想定義成抽象類就定義成抽象類的??,要滿足我們我們上面所說的定義抽象類的條件——類中提供的信息不足以描述一個對象,或者類中有無法確定的行為需要延遲到子類實現(xiàn)。
還是給大家舉個栗子。up現(xiàn)在在character包下創(chuàng)建一個Food類,將Food類定義為抽象類,并定義showNutrition()抽象方法,該方法將來要打印出食物的主要營養(yǎng),具體實現(xiàn)延遲到子類;然后分別創(chuàng)建子類Meat類和Fruit類去繼承Food類,我們在Meat類中重寫Food類的showNutrition() 方法,使其打印出肉類的主要營養(yǎng)價值;同時,另一個子類Fruit類不去實現(xiàn)showNutrition() 方法,而是將其定義為抽象類。最后,以Test類為測試類,在測試類中創(chuàng)建子類對象并調(diào)用showNutrition() 方法。
Food類,Meat類,F(xiàn)ruit類,Test類代碼如下 :
package knowledge.polymorphism.about_abstract.character; public abstract class Food { /** 父類 : Food類 */ //記住,抽象方法沒有方法體 public abstract void showNutrition(); } class Meat extends Food { /** 子類 : Meat類 */ @Override public void showNutrition() { System.out.println("肉類是蛋白質(zhì)、脂肪、維生素B2、維生素B1、煙酸和鐵的重要來源。"); } } abstract class Fruit extends Food { /** 子類 : Fruit類 */ } class Test { /** 測試類 : Test類 */ public static void main(String[] args) { Meat meat = new Meat(); meat.showNutrition(); } }
運行結(jié)果 :
我們也可以再定義一個CiLi類表示水果中的刺梨,然后讓刺梨類去繼承Fruit類,并在CiLi類中去實現(xiàn)showNutrition() 方法;Fruit類不變,Test類和CiLi類代碼如下 :
class CiLi extends Fruit { @Override public void showNutrition() { System.out.println("刺梨是當之無愧的水果界的VC之王,VC含量高達2585mg/100g!"); } } class Test { public static void main(String[] args) {/** 測試類 : Test類 */ Meat meat = new Meat(); meat.showNutrition(); System.out.println("----------------------------------------"); CiLi ciLi = new CiLi(); ciLi.showNutrition(); } }
運行結(jié)果 :
四、抽象類的成員 :
1.成員變量 :
抽象類既可以有靜態(tài)的成員變量,也可以有非靜態(tài)的成員變量。
既可以有靜態(tài)的成員常量,也可以有非靜態(tài)的成員常量。
2.成員方法 :
抽象類既可以有(非私有的)抽象方法(注意抽象方法一定是非私有非靜態(tài)非final,因為abstract關(guān)鍵字與private關(guān)鍵字,static關(guān)鍵字,final關(guān)鍵字不能同時存在);
也可以有非抽象方法(非抽象方法就可以用private,final和static關(guān)鍵字來修飾了,具體使用時,根據(jù)實際需求合理應用)。
3.構(gòu)造器 :
抽象類可以和非抽象類一樣擁有構(gòu)造器,并且支持構(gòu)造器的重載。
4.總結(jié) :
其實吧,說上面一大堆都是廢話??。
抽象類中的成員只比非抽象類多一種——抽象方法。其他都和非抽象類一樣。
大家只要記住抽象方法怎么寫,怎么用就彳亍了。??
5.代碼演示 :
up以Fruit類為演示類,代碼如下 :
package knowledge.polymorphism.about_abstract.about_members; public abstract class Fruit { //Fruit類是抽象類 //抽象類中可定義的成員: //1.非靜態(tài)變量和靜態(tài)變量 private String name = "水果名兒是有長有短"; private static String size = "水果的大小是有大有小"; //2.非靜態(tài)常量和靜態(tài)常量 public final String COLOR = "水果的顏色是五光十色"; public static final String FORM = "水果的形態(tài)是千奇百怪"; //3.抽象方法和非抽象方法 public abstract void nutrition(); private final static void suitCrowds() { System.out.println("人人都適合吃水果!"); } public void invokeSuitCrowds() { Fruit.suitCrowds(); } //4.構(gòu)造器可以重載 public Fruit() { System.out.println("Fruit's name = " + name); } public Fruit(String name) { this.name = name; } }
這些成員都可以在抽象類中定義,只要語法正確,IDEA是不會報錯的,當然,具體怎么使用這些成員就看你自己了,根據(jù)實際情況來定。 (PS : 2024--2--17補充一點——其實不太建議大家吃水果)
五、抽象類課堂練習 :
1.要求 :
如上圖所示 :
已知西風騎士團的三位騎士分別是琴,可莉和優(yōu)菈,請分別定義類來描述它們,要求給出每一個西風騎士的姓名,年齡和性別;并且,這三人均可以使用元素之力,分別是元素戰(zhàn)技和元素爆發(fā),但每位騎士的戰(zhàn)技和爆發(fā)都不一樣。其中,琴使用風元素,元素戰(zhàn)技為風壓箭,元素爆發(fā)為蒲公英之風;可莉使用火元素,元素戰(zhàn)技為蹦蹦炸彈,元素爆發(fā)為轟轟火花;優(yōu)菈使用冰元素,元素戰(zhàn)技為冰朝的渦旋,元素爆發(fā)為凝浪之光劍。請在這些類中正確選擇一個類定義成抽象類,并在該類中定義抽象方法elemental_kill() 和 elemental_burst(),要求這兩個抽象方法將來在實現(xiàn)時,需要在控制臺打印出當前騎士的元素戰(zhàn)技和元素爆發(fā);并在該抽象類中定義非抽象方法,要求該方法可以在控制臺打印出當前騎士的基本信息。
2.思路 :
①閱讀提干后我們得知,總共有三個角色,這三個角色均屬于名為“西風騎士團”的一個組織。因此,我們可以分別定義四個類來分別描述“西風騎士團”,“琴”,“可莉”,“優(yōu)菈”,再加上測試類,因此我們總共需要定義五個類。
②“西風騎士團”可以代表一類人,由于每位騎士的元素戰(zhàn)技和元素爆發(fā)均不相同,這個類并不能提供足夠的信息來描述一個具體的“騎士”對象。所以,我們可以定義Knights類來表示“西風騎士團”,并將其定義為抽象類。又因為琴,可莉,優(yōu)菈均屬于西風騎士團的一員,因此我們可以分別定義Qin類,Keli類以及Youla類來描述這三位騎士,并讓Qin類,Keli類和Youla類繼承Knights類。
③題干要求定義兩個抽象方法elemental_kill() 和 elemental_burst()來分別打印出當前騎士的元素戰(zhàn)技和元素爆發(fā)。既然我們已經(jīng)確定Knights類為抽象類,這就沒啥好說了,在Knights類中定義這兩個方法即可。
④又因為題干還要求我們在抽象類中定義方法打印出當前騎士的基本信息,因此,我們可以在Knights類定義name,age,sex這些屬性;根據(jù)JavaBean標準,我們需要將這些屬性全部設(shè)為私有,并給出公共的訪問這些屬性的方法,然后給出Knights類的無參構(gòu)造和帶參構(gòu)造(注意,Knights是抽象類,無法被實例化,因此我們給出Knights構(gòu)造器的目的不是為了創(chuàng)建Knights類對象,而是為了在子類的帶參構(gòu)造中使用super語句調(diào)用父類構(gòu)造器;接著,再定義一個printInfo方法,用于打印出當前騎士的姓名,年齡和性別。
⑤最后,我們可以定義測試類Test類,并分別創(chuàng)建Qin類,Keli類和Youla類對象,調(diào)用elemental_kill()方法,elemental_burst() 方法,以及printInfo方法。
3.代碼 :
代碼如下 :
package knowledge.polymorphism.about_abstract.exercise; public abstract class Knights { /** 騎士類 */ private String name; private int age; private String sex; public Knights() { } public Knights(String name, int age, String sex) { this.name = name; this.age = age; this.sex = sex; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public abstract void elemental_skill(); public abstract void elemental_burst(); public void printInfo() { System.out.println("西風騎士——" + getName() + "," + getAge() + "歲,性別" + getSex()); } } class Qin extends Knights{ /** 琴類 */ public Qin(String name, int age, String sex) { super(name, age, sex); } @Override public void elemental_skill() { System.out.println("琴的元素戰(zhàn)技是風壓箭。"); } @Override public void elemental_burst() { System.out.println("琴的元素戰(zhàn)技是蒲公英之風。"); } } class Keli extends Knights{ /** 可莉類 */ public Keli(String name, int age, String sex) { super(name, age, sex); } @Override public void elemental_skill() { System.out.println("可莉的元素戰(zhàn)技是蹦蹦炸彈。"); } @Override public void elemental_burst() { System.out.println("可莉的元素戰(zhàn)技是轟轟火花。"); } } class Youla extends Knights{ /** 優(yōu)菈類 */ public Youla(String name, int age, String sex) { super(name, age, sex); } @Override public void elemental_skill() { System.out.println("優(yōu)菈的元素戰(zhàn)技是冰朝的渦旋。"); } @Override public void elemental_burst() { System.out.println("優(yōu)菈的元素戰(zhàn)技是凝浪之光劍。"); } } class Test { /** 測試類 */ public static void main(String[] args) { Qin qin = new Qin("琴", 22, "female"); qin.elemental_skill(); qin.elemental_burst(); qin.printInfo(); System.out.println("-------------------------------------------"); Keli keli = new Keli("可莉", 500, "female"); keli.elemental_skill(); keli.elemental_burst(); keli.printInfo(); System.out.println("-------------------------------------------"); Youla youla = new Youla("優(yōu)菈", 21, "female"); youla.elemental_skill(); youla.elemental_burst(); youla.printInfo(); } }
運行結(jié)果 :
六、總結(jié) :
??,以上就是本節(jié)抽象類相關(guān)的全部內(nèi)容了,大家一定要牢記抽象類和抽象方法的特點,牢記抽象類和抽象方法之間的關(guān)系,掌握abstract關(guān)鍵字的使用。下一節(jié)內(nèi)容是多態(tài)篇章的final關(guān)鍵字,我們不見不散??。感謝閱讀!
System.out.println("END--------------------------------------------------------------------------------");
到此這篇關(guān)于java 抽象類 詳解的文章就介紹到這了,更多相關(guān)java 抽象類 詳解內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
idea中開啟Run Dashboard 和 快速復制項目并改變端口的方法
這篇文章主要介紹了idea中開啟Run Dashboard 和 快速復制項目并改變端口的方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-08-08基于Spring Data Jest的Elasticsearch數(shù)據(jù)統(tǒng)計示例
本篇文章主要介紹了基于Spring Data Jest的Elasticsearch數(shù)據(jù)統(tǒng)計示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-02-02Springboot詳解整合SpringSecurity實現(xiàn)全過程
Spring Security基于Spring開發(fā),項目中如果使用Springboot作為基礎(chǔ),配合Spring Security做權(quán)限更加方便,而Shiro需要和Spring進行整合開發(fā)。因此作為spring全家桶中的Spring Security在java領(lǐng)域很常用2022-07-07解決Springboot配置excludePathPatterns不生效的問題
這篇文章主要介紹了解決Springboot配置excludePathPatterns不生效的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-10-10java生成字母數(shù)字組合的隨機數(shù)示例 java生成隨機數(shù)
這篇文章主要介紹了java生成字母數(shù)字組合的隨機數(shù)的示例,大家參考使用吧2014-01-01