請用面向?qū)ο蟮乃枷耄勔徽勥@次面試的過程-創(chuàng)新互聯(lián)

二哥,究竟什么是面向?qū)ο竽??還有,什么是面向過程。今天去面試的時(shí)候,面試官讓我用面向?qū)ο蟮乃枷胝勔徽勥@次面試的過程。

專注于為中小企業(yè)提供網(wǎng)站設(shè)計(jì)制作、成都做網(wǎng)站服務(wù),電腦端+手機(jī)端+微信端的三站合一,更高效的管理,為中小企業(yè)宿城免費(fèi)做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動(dòng)了成百上千企業(yè)的穩(wěn)健成長,幫助中小企業(yè)通過網(wǎng)站建設(shè)實(shí)現(xiàn)規(guī)模擴(kuò)充和轉(zhuǎn)變。

前兩天,讀者秋秋問我了我上面這個(gè)問題。

看到這個(gè)問題后,我思考了好一會(huì)兒,總覺得面試官的問法有點(diǎn)問題:為什么要用面向?qū)ο蟮乃枷胝勔徽劽嬖嚨摹斑^程”?

有點(diǎn)矛盾,有沒有?先不管這么多了,且來看看什么是面向?qū)ο蟀伞?/p>

01、面向?qū)ο?/h4>

很久沒有思考過什么是面向?qū)ο筮@個(gè)問題了,就好像很久沒有吃過烤紅薯一樣,那股香味究竟是什么,已經(jīng)很難準(zhǔn)確地形容出來了。腦海中只浮現(xiàn)出這樣一幅圖:

請用面向?qū)ο蟮乃枷?,談一談這次面試的過程

一開始的時(shí)候,并沒有面向?qū)ο?,只有面向過程的概念。我們回到秋秋面試的話題上,把面試前(可以降低需求的復(fù)雜性)的過程簡單地拆解一下。

  • 秋秋投遞簡歷
  • 面試官收到秋秋的簡歷
  • 面試官通知秋秋面試

為了實(shí)現(xiàn)這 3 個(gè)步驟,我們定義 3 個(gè)方法,并依次調(diào)用:

  • qiuqiuDeliverResume();
  • interviewerReceiveResume();
  • interviewerNotifyQiuqiu();

但是,假如參加面試的不是秋秋,這 3 個(gè)方法就要重新定義了(莫抬杠),盡管步驟并沒有變。面向?qū)ο髲牧硪粋€(gè)角度來解決這個(gè)問題,它把對象(對事物的一種抽象描述)作為程序的基本單元。

回到秋秋面試的例子,用面向?qū)ο蟮乃枷雭韺?shí)現(xiàn),就需要先定義 2 個(gè)類(類是構(gòu)建對象的藍(lán)圖,里面包含若干的數(shù)據(jù)和操作這些數(shù)據(jù)的方法),分別是應(yīng)聘者和面試官。

應(yīng)聘者可以投遞簡歷;面試官可以接收應(yīng)聘者的簡歷和通知應(yīng)聘者前來面試。然后再通過類創(chuàng)建兩個(gè)對象,分別是秋秋和他的面試官;對象創(chuàng)建成功后,就可以依次調(diào)用對應(yīng)的方法完成上述的 3 個(gè)步驟。

面向?qū)ο螅ㄓ⒄Z:Object Oriented,縮寫:OO)思想是一種試圖降低代碼間的依賴,應(yīng)對復(fù)雜性,從而解決代碼重用的軟件設(shè)計(jì)思想——恰好解決了面向過程帶來的問題。

面向?qū)ο笥泻芏嘀匾奶匦?,比如說封裝、繼承和多態(tài)。這些概念又該怎么理解呢?所謂一圖勝千言,我給你來一張有趣的、形象的。

請用面向?qū)ο蟮乃枷耄勔徽勥@次面試的過程

了解了面向?qū)ο蟮乃枷牒螅覀儊硗ㄟ^具體的代碼完成秋秋面試前的 3 個(gè)步驟。并對類和對象的相關(guān)知識(shí)點(diǎn)進(jìn)行歸納和總結(jié)。

02、應(yīng)聘者

先來細(xì)致地看一下應(yīng)聘者類——Candidate.java。

package com.cmower

class Candidate {
    private String name;

    public Candidate(String name) {
        this.name = name;
    }

    public void deliverResume() {
        System.out.println(getName() + "發(fā)簡歷");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

Candidate 包含了類的 4 個(gè)重要概念:

  • 成員變量(有時(shí)叫做域,有時(shí)叫做字段,有時(shí)叫做屬性)name;
  • 成員變量訪問器(有時(shí)叫做 getter/settergetName()setName()
  • 構(gòu)造方法(有時(shí)叫做構(gòu)造器)Candidate();
  • 普通方法 deliverResume()。

Candidate 類雖然簡單,但卻大有學(xué)問。

1)為了保證包名的絕對唯一,Sun 公司建議將域名(絕對是獨(dú)一無二的)以逆序的形式作為包名——這也是為什么包名經(jīng)常以 org、com 開頭的原因(是不是有一種豁然開朗的感覺)。我曾申請過一個(gè)域名,叫 cmower.com,所以我個(gè)人編寫的絕大多數(shù)代碼都是在 com.cmower包下。

2)類的方法定義順序依次是:構(gòu)造方法 > 公有(public)方法或保護(hù)(protected)方法 > 私有(private)方法 > getter/setter 方法。

構(gòu)造方法是創(chuàng)建對象的必經(jīng)之路,放在首位是必須的。如果只有系統(tǒng)默認(rèn)的無參構(gòu)造方法,可忽略。

公有方法是類的調(diào)用者和維護(hù)者最關(guān)心的方法,應(yīng)該在比較靠前的位置展示;保護(hù)方法雖然只有子類關(guān)心,也可能是“模板設(shè)計(jì)模式”下的核心方法,所以也要靠前;私有方法只對本類可見,一般不需要特別關(guān)心,所以往后放;getter/setter 方法承載的信息價(jià)值較低,所以放在類的最后面。

3)setter 方法中,參數(shù)名稱與成員變量名稱保持一致,采用 this.成員名 = 參數(shù)名 的形式。

4)成員變量不要用 public 修飾,盡量用 private 修飾;如果需要被子類繼承,可以用 protected 修飾。

在初學(xué) Java 編程的時(shí)候,我經(jīng)常產(chǎn)生一個(gè)疑惑:為什么不使用 public 修飾成員變量呢?這樣做不是比 getter/setter 更方便嗎?

我最先想到的答案是這樣的:

請用面向?qū)ο蟮乃枷耄勔徽勥@次面試的過程

解釋:如果只有 private String name 而沒有 getter/setter 的話,Eclipse 會(huì)提示 The value of the field Candidate.name is not used 的警告。

當(dāng)然了,這樣的答案過于牽強(qiáng)。那能不能來個(gè)靠譜點(diǎn)的答案呢?

能,為了體現(xiàn)封裝的思想:將數(shù)據(jù)與行為進(jìn)行分離。封裝有什么好處呢?

  • 隱藏類的實(shí)現(xiàn)細(xì)節(jié);
  • 讓使用者只能通過事先定制好的方法(getter/setter)來訪問數(shù)據(jù),可以方便地加入控制方法,限制對成員變量的不合理操作;
  • 便于修改,增強(qiáng)代碼的維護(hù)性和健壯性;
  • 提高代碼的安全性和規(guī)范性;
  • 使程序更加具備穩(wěn)定性和可拓展性。

不過,我對這些嚴(yán)肅的詞匯和科學(xué)用語實(shí)在是提不起半點(diǎn)興致。那就再換一個(gè)答案吧。

套用《Java 開發(fā)實(shí)戰(zhàn)經(jīng)典》中舉過的一個(gè)例子,我們增加一個(gè)應(yīng)聘者年齡的共有成員變量 age。

class Candidate {
    public int age;
}

然后在創(chuàng)建應(yīng)聘者對象的時(shí)候,直接通過類成員變量賦值:new Candidate().age = -99; 這樣賦值是沒有任何問題的,但沒有實(shí)際的意義,年齡是不可能為負(fù)數(shù)的。為了防止出現(xiàn)這樣的錯(cuò)誤,可以對它進(jìn)行封裝,也就是私有化,然后在 setter 方法中對年齡進(jìn)行判斷,代碼如下:

class Candidate {
    private int age;

    public void setAge(int age) {
      if (age >= 0) {
        this.age = age;
      }
    }
}

這個(gè)答案你覺得滿意嗎?我最開始看到這個(gè)答案的時(shí)候覺得很滿意。但看了《阿里巴巴 Java 開發(fā)手冊》后(詳情截圖如下),就覺得不滿意了。

請用面向?qū)ο蟮乃枷?,談一談這次面試的過程

第一,類成員變量使用基本類型很容易造成NullPointException的錯(cuò)誤;第二,在 getter/setter 增加業(yè)務(wù)邏輯的確很容易把實(shí)際的問題隱藏起來。

那,好的答案究竟是什么呢?

如果設(shè)置成員變量為 public,那么每個(gè)調(diào)用者都可以讀寫它,但如果以 private 配合 getter/setter 的形式訪問時(shí),就可以達(dá)到“不準(zhǔn)訪問”、“只讀訪問”、“讀寫訪問”以及“只寫訪問”的目的。因?yàn)椴皇敲總€(gè)成員變量都需要 getter/setter。

5)每個(gè)類都至少會(huì)有一個(gè)構(gòu)造方法。初學(xué)者可能會(huì)非常疑惑:我的那個(gè)類真的沒有構(gòu)造方法?。?/p>

如果在編寫一個(gè)類的時(shí)候沒有編寫構(gòu)造方法,那么系統(tǒng)就會(huì)提供一個(gè)無參的構(gòu)造方法,就好像是這樣:

class Candidate {
    private String name;

    public Candidate() {
    }

}

當(dāng)執(zhí)行 new Candidate() 的時(shí)候,成員變量 name 就會(huì)被初始化為 null。一般情況下,我們會(huì)為類設(shè)置它必須的構(gòu)造方法,然后在創(chuàng)建對象的時(shí)候?qū)Τ蓡T變量進(jìn)行賦值。

03、面試官

再來粗略地看一下面試官類——Interviewer.java。

class Interviewer {
    private Candidate candidate;

    public Interviewer (Candidate candidate) {
        this.candidate = candidate;
    }

    public void receviveResume() {
        System.out.println("收到" + getCandidate().getName() + "簡歷");
    }

    public void notifyInterview() {
        System.out.println("通知" + getCandidate().getName() + "面試");
    }

    public Candidate getCandidate() {
        return candidate;
    }

    public void setCandidate(Candidate candidate) {
        this.candidate = candidate;
    }

}

Interviewer 有一個(gè)成員變量 Candidate,一個(gè)構(gòu)造方法,兩個(gè)共有方法,以及成員變量對應(yīng)的 getter/setter。

(這段代碼存在一個(gè)嚴(yán)重的問題,你注意到了嗎?)

04、測試

然后,我們讓應(yīng)聘者發(fā)送簡歷,讓面試官接收簡歷并發(fā)送通知。

Candidate qiuqiu = new Candidate("秋秋");
// 發(fā)送簡歷
qiuqiu.deliverResume();

Interviewer interviewer = new Interviewer(qiuqiu);
// 面試官接收到簡歷
interviewer.receviveResume();
// 面試官通知應(yīng)聘者來面試
interviewer.notifyInterview();

在初學(xué) Java 的很長一段時(shí)間里,我總是搞不清楚什么是“對象”,什么是“引用”,差點(diǎn)因此放棄我的程序生涯。后來,在網(wǎng)上認(rèn)識(shí)了一個(gè)大佬,人稱老王,是他挽救了我的程序生涯。

他解釋說。

Candidate qiuqiu = new Candidate("秋秋"); 可以拆分為兩行代碼:

Candidate qiuqiu;
qiuqiu = new Candidate("秋秋");

第一行代碼 Candidate qiuqiu; 中的 qiuqiu 這時(shí)候可以稱作是對象變量,它暫時(shí)還沒有引用任何對象,嚴(yán)格意義上,它也不能稱為 null 。

第二行代碼 qiuqiu = new Candidate("秋秋"); 可以拆分為兩個(gè)部分,= 號(hào)左側(cè)和 = 號(hào)右側(cè)。

右側(cè)的表達(dá)式 new Candidate("秋秋") 先執(zhí)行,執(zhí)行完后,會(huì)在堆上創(chuàng)建了一個(gè) name 為“秋秋”的對象,類型為 Candidate,表達(dá)式 new Candidate("秋秋") 的值是新創(chuàng)建對象的引用。

然后再把這個(gè)引用通過 = 操作符賦值給左側(cè)的對象變量 qiuqiu,賦值后,qiuqiu就不再是對象變量了,應(yīng)該稱為對象引用。

請用面向?qū)ο蟮乃枷?,談一談這次面試的過程

看完老王的解釋,你會(huì)不會(huì)情不自禁地“哦,原來如此??!”反正我當(dāng)時(shí)頓悟的時(shí)候是這樣的。

前面提到,Interviewer 類的設(shè)計(jì)存在一個(gè)嚴(yán)重的問題,是什么呢?

Candidate qiuqiu = new Candidate("秋秋");
Interviewer interviewer = new Interviewer(qiuqiu);

interviewer.getCandidate().setName("夏夏");
System.out.println(qiuqiu.getName());

這段代碼執(zhí)行完后,你會(huì)發(fā)現(xiàn)秋秋變成了夏夏,應(yīng)聘者的私有成員變量 name 竟然被改變了!問題的原因也很簡單,qiuqiu 和 interviewer.getCandidate() 引用了同一個(gè)對象。

請用面向?qū)ο蟮乃枷?,談一談這次面試的過程

那怎么解決呢?當(dāng) getter 需要返回一個(gè)可變對象的引用時(shí),應(yīng)該先進(jìn)行克隆(clone)。以下展示了一個(gè)非常簡單的克隆方案。

class Interviewer {
    private Candidate candidate;

    public Interviewer (Candidate candidate) {
        this.candidate = candidate;
    }

    public Candidate getCandidate() {
        Candidate candidate = new Candidate(this.candidate.getName());
        return candidate;
    }

}

05、最后

這篇文章花了 5 個(gè)多小時(shí)才寫完,此刻我的感覺只有一個(gè)字——餓,我要出去吃飯了。吃飯之前,我決定先買個(gè)烤紅薯吃,重溫一下那種久違的香。

上一篇:Java面試官:兄弟,你確定double精度比float低嗎?

下一篇:再談 Java 的繼承和超類 Object

謝謝大家的閱讀,原創(chuàng)不易,喜歡就隨手點(diǎn)個(gè)贊

另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場景需求。

新聞名稱:請用面向?qū)ο蟮乃枷?,談一談這次面試的過程-創(chuàng)新互聯(lián)
分享鏈接:http://bm7419.com/article32/dihcpc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供企業(yè)建站、品牌網(wǎng)站建設(shè)、關(guān)鍵詞優(yōu)化面包屑導(dǎo)航、ChatGPT、動(dòng)態(tài)網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

手機(jī)網(wǎng)站建設(shè)