小白泳梆,你要的Java抽象類鳖悠,操碎了心!

自從給小白寫了兩篇科普性質(zhì)的文章后优妙,我就有點(diǎn)一發(fā)不可收拾乘综,覺(jué)得很有必要繼續(xù)寫下去。因?yàn)橛凶x者留言“鼓勵(lì)”我說(shuō)套硼,“二哥卡辰,你真的是為小白操碎了心啊邪意!”我容易嗎九妈?我。

當(dāng)我們要完成的任務(wù)是確定的雾鬼,但具體的方式需要隨后開(kāi)個(gè)會(huì)投票的話萌朱,Java 的抽象類就派上用場(chǎng)了。這句話怎么理解呢策菜?搬個(gè)小板凳坐好晶疼,聽(tīng)我來(lái)給你講講。

01又憨、抽象類的 5 個(gè)關(guān)鍵點(diǎn)

1)定義抽象類的時(shí)候需要用到關(guān)鍵字 abstract翠霍,放在 class 關(guān)鍵字前。

public abstract class AbstractPlayer {
}

關(guān)于抽象類的命名蠢莺,阿里出品的 Java 開(kāi)發(fā)手冊(cè)上有強(qiáng)調(diào)寒匙,“抽象類命名要使用 Abstract 或 Base 開(kāi)頭”,記住了哦躏将。

2)抽象類不能被實(shí)例化锄弱,但可以有子類考蕾。

嘗試通過(guò) new 關(guān)鍵字實(shí)例化的話,編譯器會(huì)報(bào)錯(cuò)棵癣,提示“類是抽象的辕翰,不能實(shí)例化”夺衍。

通過(guò) extends 關(guān)鍵字可以繼承抽象類狈谊,繼承后,BasketballPlayer 類就是 AbstractPlayer 的子類沟沙。

public class BasketballPlayer extends AbstractPlayer {
}

3)如果一個(gè)類定義了一個(gè)或多個(gè)抽象方法河劝,那么這個(gè)類必須是抽象類。

當(dāng)在一個(gè)普通類(沒(méi)有使用 abstract 關(guān)鍵字修飾)中定義了抽象方法矛紫,編譯器就會(huì)有兩處錯(cuò)誤提示赎瞎。

第一處在類級(jí)別上,提醒你“這個(gè)類必須通過(guò) abstract 關(guān)鍵字定義”颊咬,or 的那個(gè)信息沒(méi)必要务甥,見(jiàn)下圖。

第二處在方法級(jí)別上喳篇,提醒你“抽象方法所在的類不是抽象的”敞临,見(jiàn)下圖。

4)抽象類可以同時(shí)聲明抽象方法和具體方法麸澜,也可以什么方法都沒(méi)有挺尿,但沒(méi)必要。就像下面這樣:

public abstract class AbstractPlayer {
    abstract void play();
    
    public void sleep() {
        System.out.println("運(yùn)動(dòng)員也要休息而不是挑戰(zhàn)極限");
    }
}

5)抽象類派生的子類必須實(shí)現(xiàn)父類中定義的抽象方法炊邦。比如說(shuō)编矾,抽象類中定義了 play() 方法,子類中就必須實(shí)現(xiàn)馁害。

public class BasketballPlayer extends AbstractPlayer {
    @Override
    void play() {
        System.out.println("我是張伯倫窄俏,籃球場(chǎng)上得過(guò) 100 分");
    }
}

如果沒(méi)有實(shí)現(xiàn)的話,編譯器會(huì)提醒你“子類必須實(shí)現(xiàn)抽象方法”碘菜,見(jiàn)下圖凹蜈。

02、什么時(shí)候用抽象類

與抽象類息息相關(guān)的還有一個(gè)概念炉媒,就是接口踪区,我們留到下一篇文章中詳細(xì)說(shuō),因?yàn)橐f(shuō)的知識(shí)點(diǎn)還是蠻多的吊骤。你現(xiàn)在只需要有這樣一個(gè)概念就好缎岗,接口是對(duì)行為的抽象,抽象類是對(duì)整個(gè)類(包含成員變量和行為)進(jìn)行抽象白粉。

(是不是有點(diǎn)明白又有點(diǎn)不明白传泊,別著急鼠渺,翹首以盼地等下一篇文章出爐吧)

除了接口之外,還有一個(gè)概念就是具體的類眷细,就是不通過(guò) abstract 修飾的普通類拦盹,見(jiàn)下面這段代碼中的定義。

public class BasketballPlayer {
   public void play() {
        System.out.println("我是詹姆斯溪椎,現(xiàn)役第一人");
    }
}

有接口普舆,有具體類,那什么時(shí)候該使用抽象類呢校读?

1)我們希望一些通用的功能被多個(gè)子類復(fù)用沼侣。比如說(shuō),AbstractPlayer 抽象類中有一個(gè)普通的方法 sleep()歉秫,表明所有運(yùn)動(dòng)員都需要休息蛾洛,那么這個(gè)方法就可以被子類復(fù)用。

public abstract class AbstractPlayer {
    public void sleep() {
        System.out.println("運(yùn)動(dòng)員也要休息而不是挑戰(zhàn)極限");
    }
}

雖然 AbstractPlayer 類可以不是抽象類——把 abstract 修飾符去掉也能滿足這種場(chǎng)景雁芙。但 AbstractPlayer 類可能還會(huì)有一個(gè)或者多個(gè)抽象方法轧膘。

BasketballPlayer 繼承了 AbstractPlayer 類,也就擁有了 sleep() 方法兔甘。

public class BasketballPlayer extends AbstractPlayer {
}

BasketballPlayer 對(duì)象可以直接調(diào)用 sleep() 方法:

BasketballPlayer basketballPlayer = new BasketballPlayer();
basketballPlayer.sleep();

FootballPlayer 繼承了 AbstractPlayer 類谎碍,也就擁有了 sleep() 方法。

public class FootballPlayer extends AbstractPlayer {
}

FootballPlayer 對(duì)象也可以直接調(diào)用 sleep() 方法:

FootballPlayer footballPlayer = new FootballPlayer();
footballPlayer.sleep();

2)我們需要在抽象類中定義好 API裂明,然后在子類中擴(kuò)展實(shí)現(xiàn)椿浓。比如說(shuō),AbstractPlayer 抽象類中有一個(gè)抽象方法 play()闽晦,定義所有運(yùn)動(dòng)員都可以從事某項(xiàng)運(yùn)動(dòng)扳碍,但需要對(duì)應(yīng)子類去擴(kuò)展實(shí)現(xiàn)。

public abstract class AbstractPlayer {
    abstract void play();
}

BasketballPlayer 繼承了 AbstractPlayer 類仙蛉,擴(kuò)展實(shí)現(xiàn)了自己的 play() 方法笋敞。

public class BasketballPlayer extends AbstractPlayer {
    @Override
    void play() {
        System.out.println("我是張伯倫,我籃球場(chǎng)上得過(guò) 100 分荠瘪,");
    }
}

FootballPlayer 繼承了 AbstractPlayer 類夯巷,擴(kuò)展實(shí)現(xiàn)了自己的 play() 方法。

public class FootballPlayer extends AbstractPlayer {
    @Override
    void play() {
        System.out.println("我是C羅哀墓,我能接住任意高度的頭球");
    }
}

3)如果父類與子類之間的關(guān)系符合 is-a 的層次關(guān)系趁餐,就可以使用抽象類,比如說(shuō)籃球運(yùn)動(dòng)員是運(yùn)動(dòng)員篮绰,足球運(yùn)動(dòng)員是運(yùn)動(dòng)員后雷。

03、具體示例

為了進(jìn)一步展示抽象類的特性,我們?cè)賮?lái)看一個(gè)具體的示例臀突。假設(shè)現(xiàn)在有一個(gè)文件勉抓,里面的內(nèi)容非常簡(jiǎn)單——“Hello World”,現(xiàn)在需要有一個(gè)讀取器將內(nèi)容讀取出來(lái)候学,最好能按照大寫的方式藕筋,或者小寫的方式。

這時(shí)候梳码,最好定義一個(gè)抽象類隐圾,比如說(shuō) BaseFileReader:

public abstract class BaseFileReader {
    protected Path filePath;

    protected BaseFileReader(Path filePath) {
        this.filePath = filePath;
    }

    public List<String> readFile() throws IOException {
        return Files.lines(filePath)
                .map(this::mapFileLine).collect(Collectors.toList());
    }

    protected abstract String mapFileLine(String line);
}

filePath 為文件路徑,使用 protected 修飾边翁,表明該成員變量可以在需要時(shí)被子類訪問(wèn)翎承。

readFile() 方法用來(lái)讀取文件,方法體里面調(diào)用了抽象方法 mapFileLine()——需要子類擴(kuò)展實(shí)現(xiàn)大小寫的方式符匾。

你看,BaseFileReader 設(shè)計(jì)的就非常合理瘩例,并且易于擴(kuò)展啊胶,子類只需要專注于具體的大小寫實(shí)現(xiàn)方式就可以了。

小寫的方式:

public class LowercaseFileReader extends BaseFileReader {
    protected LowercaseFileReader(Path filePath) {
        super(filePath);
    }

    @Override
    protected String mapFileLine(String line) {
        return line.toLowerCase();
    }
}

大寫的方式:

public class UppercaseFileReader extends BaseFileReader {
    protected UppercaseFileReader(Path filePath) {
        super(filePath);
    }

    @Override
    protected String mapFileLine(String line) {
        return line.toUpperCase();
    }
}

你看垛贤,從文件里面一行一行讀取內(nèi)容的代碼被子類復(fù)用了——抽象類 BaseFileReader 類中定義的普通方法 readFile()焰坪。與此同時(shí),子類只需要專注于自己該做的工作聘惦,LowercaseFileReader 以小寫的方式讀取文件內(nèi)容某饰,UppercaseFileReader 以大寫的方式讀取文件內(nèi)容。

接下來(lái)善绎,我們來(lái)新建一個(gè)測(cè)試類 FileReaderTest:

public class FileReaderTest {
    public static void main(String[] args) throws URISyntaxException, IOException {
        URL location = FileReaderTest.class.getClassLoader().getResource("helloworld.txt");
        Path path = Paths.get(location.toURI());
        BaseFileReader lowercaseFileReader = new LowercaseFileReader(path);
        BaseFileReader uppercaseFileReader = new UppercaseFileReader(path);
        System.out.println(lowercaseFileReader.readFile());
        System.out.println(uppercaseFileReader.readFile());
    }
}

項(xiàng)目的 resource 目錄下有一個(gè)文本文件黔漂,名字叫 helloworld.txt。

可以通過(guò) ClassLoader.getResource() 的方式獲取到該文件的 URI 路徑禀酱,然后就可以使用 LowercaseFileReader 和 UppercaseFileReader 兩種方式讀取到文本內(nèi)容了炬守。

輸出結(jié)果如下所示:

[hello world]
[HELLO WORLD]

好了,我親愛(ài)的讀者朋友剂跟,以上就是本文的全部?jī)?nèi)容了减途。是不是感覺(jué)認(rèn)知邊界又拓寬了?

我是沉默王二曹洽,一枚有趣的程序員鳍置。如果覺(jué)得文章對(duì)你有點(diǎn)幫助,請(qǐng)微信搜索「 沉默王二 」第一時(shí)間閱讀送淆,回復(fù)【666】更有我為你精心準(zhǔn)備的 500G 高清教學(xué)視頻(已分門別類)税产。

本文 GitHub 已經(jīng)收錄,有大廠面試完整考點(diǎn),歡迎 Star砖第。

原創(chuàng)不易撤卢,莫要白票,請(qǐng)你為本文點(diǎn)個(gè)贊吧梧兼,這將是我寫作更多優(yōu)質(zhì)文章的最強(qiáng)動(dòng)力放吩。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市羽杰,隨后出現(xiàn)的幾起案子渡紫,更是在濱河造成了極大的恐慌,老刑警劉巖考赛,帶你破解...
    沈念sama閱讀 218,204評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件惕澎,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡颜骤,警方通過(guò)查閱死者的電腦和手機(jī)唧喉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)忍抽,“玉大人八孝,你說(shuō)我怎么就攤上這事○睿” “怎么了干跛?”我有些...
    開(kāi)封第一講書人閱讀 164,548評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)祟绊。 經(jīng)常有香客問(wèn)我楼入,道長(zhǎng),這世上最難降的妖魔是什么牧抽? 我笑而不...
    開(kāi)封第一講書人閱讀 58,657評(píng)論 1 293
  • 正文 為了忘掉前任嘉熊,我火速辦了婚禮,結(jié)果婚禮上阎姥,老公的妹妹穿的比我還像新娘记舆。我一直安慰自己,他們只是感情好呼巴,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,689評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布泽腮。 她就那樣靜靜地躺著,像睡著了一般衣赶。 火紅的嫁衣襯著肌膚如雪诊赊。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 51,554評(píng)論 1 305
  • 那天府瞄,我揣著相機(jī)與錄音碧磅,去河邊找鬼碘箍。 笑死,一個(gè)胖子當(dāng)著我的面吹牛鲸郊,可吹牛的內(nèi)容都是我干的丰榴。 我是一名探鬼主播,決...
    沈念sama閱讀 40,302評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼秆撮,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼四濒!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起职辨,我...
    開(kāi)封第一講書人閱讀 39,216評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤盗蟆,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后舒裤,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體喳资,經(jīng)...
    沈念sama閱讀 45,661評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,851評(píng)論 3 336
  • 正文 我和宋清朗相戀三年腾供,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了仆邓。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,977評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡台腥,死狀恐怖宏赘,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情黎侈,我是刑警寧澤,帶...
    沈念sama閱讀 35,697評(píng)論 5 347
  • 正文 年R本政府宣布闷游,位于F島的核電站峻汉,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏脐往。R本人自食惡果不足惜休吠,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,306評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望业簿。 院中可真熱鬧瘤礁,春花似錦、人聲如沸梅尤。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,898評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)巷燥。三九已至赡盘,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間缰揪,已是汗流浹背陨享。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,019評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人抛姑。 一個(gè)月前我還...
    沈念sama閱讀 48,138評(píng)論 3 370
  • 正文 我出身青樓赞厕,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親定硝。 傳聞我的和親對(duì)象是個(gè)殘疾皇子皿桑,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,927評(píng)論 2 355