国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Java入門高頻考查基礎(chǔ)知識(shí)4(字節(jié)跳動(dòng)面試題18題2.5萬(wàn)字參考答案)

這篇具有很好參考價(jià)值的文章主要介紹了Java入門高頻考查基礎(chǔ)知識(shí)4(字節(jié)跳動(dòng)面試題18題2.5萬(wàn)字參考答案)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

Java 是一種廣泛使用的面向?qū)ο缶幊陶Z(yǔ)言,在軟件開(kāi)發(fā)領(lǐng)域有著重要的地位。Java 提供了豐富的庫(kù)和強(qiáng)大的特性,適用于多種應(yīng)用場(chǎng)景,包括企業(yè)應(yīng)用、移動(dòng)應(yīng)用、嵌入式系統(tǒng)等。

????????

以下是幾個(gè)面試技巧:

? ?1. 復(fù)習(xí)核心概念:回顧 Java 的核心概念,如面向?qū)ο缶幊?、類和?duì)象、繼承和多態(tài)、異常處理、集合框架等。確保對(duì)這些基礎(chǔ)知識(shí)有清晰的理解。

? ?2. 熟悉常見(jiàn)問(wèn)題:預(yù)測(cè)并準(zhǔn)備常見(jiàn)的面試問(wèn)題,如 "什么是 Java 的封裝、繼承和多態(tài)?","什么是抽象類和接口?它們的區(qū)別是什么?" 等。熟悉這些問(wèn)題的答案,以便能夠流利、清晰地回答面試官的提問(wèn)。

? ?3. 編碼實(shí)踐:練習(xí)編寫(xiě)一些簡(jiǎn)單的 Java 代碼,以加深對(duì)基礎(chǔ)概念的理解。嘗試解決一些常見(jiàn)的編程問(wèn)題,如逆序字符串、查找數(shù)組中的最大值等。這將有助于您在面試中展示自己的編碼能力。

? ?4. 項(xiàng)目經(jīng)驗(yàn)準(zhǔn)備:復(fù)習(xí)您在 Java 開(kāi)發(fā)方面的項(xiàng)目經(jīng)驗(yàn)。準(zhǔn)備一些項(xiàng)目細(xì)節(jié)和亮點(diǎn),強(qiáng)調(diào)您在項(xiàng)目中所承擔(dān)的角色和技術(shù)貢獻(xiàn)。面試官通常會(huì)關(guān)注您的項(xiàng)目經(jīng)驗(yàn),因此務(wù)必能夠清晰而有條理地介紹您的項(xiàng)目經(jīng)歷。

? ?5. 注意優(yōu)缺點(diǎn):在回答問(wèn)題時(shí),盡量不僅停留在正確的答案上,還要深入思考并表達(dá)特定功能、概念或語(yǔ)言特性的優(yōu)缺點(diǎn)。面試官通常會(huì)更關(guān)注您的思考能力和對(duì)技術(shù)的全面理解。

? ?6. 積極參與:在面試中,積極與面試官互動(dòng)。表達(dá)自己的觀點(diǎn)和思考,提出問(wèn)題或?qū)で蟪吻?。這不僅能展示您的積極性和好奇心,還能促進(jìn)面試的互動(dòng)和對(duì)話。

? ?7. 準(zhǔn)備好問(wèn)題:在面試結(jié)束時(shí),通常會(huì)給您提供機(jī)會(huì)提問(wèn)。為了展示您對(duì)崗位和公司的興趣,準(zhǔn)備一些相關(guān)問(wèn)題,例如關(guān)于公司文化、技術(shù)棧、團(tuán)隊(duì)合作等方面的問(wèn)題。

????????

最重要的是保持自信和冷靜。提前準(zhǔn)備,并對(duì)自己的知識(shí)和經(jīng)驗(yàn)有自信,這樣您就能在面試中展現(xiàn)出最佳的表現(xiàn)。祝您面試順利!

目錄

一、Java Object類有哪些方法,分別作用

二、HashMap原理,是否存在線程安全問(wèn)題

三、Java如何進(jìn)?線程同步

四、CAS原理

五、JVM垃圾回收之GC算法有哪些

六、Mysql索引原理以及查詢優(yōu)化

七、TCP擁塞控制

八、算法:? 給定—棵二叉樹(shù),找到這棵樹(shù)最中最后—行中最左邊的值

九、知道什么設(shè)計(jì)模式,分別介紹

十、算法:求?序數(shù)組中第k?的數(shù)

十一、算法:求旋轉(zhuǎn)數(shù)組找最?值(?分法)

十二、算法:判斷?叉樹(shù)是否鏡像(遞歸)

十三、如何理解前后端分離

十四、有哪些后端開(kāi)發(fā)經(jīng)驗(yàn),做了什么

十五、介紹HashMap與TreeMap區(qū)別

十六、?HashMap實(shí)現(xiàn)?個(gè)有過(guò)期功能的緩存

十七、平時(shí)怎么學(xué)習(xí)新知識(shí)

十八、最近看了什么書(shū)


(一面題)

一、Java Object類有哪些方法,分別作用

????????Java中的Object類是所有類的超類(父類),任何類都直接或間接地繼承自Object類。因此,Object類中的方法對(duì)所有Java對(duì)象都是可用的。下面是一些最常用的Object類方法及其作用:

?1. public boolean equals(Object obj)

  • 檢查調(diào)用該方法的對(duì)象是否等于參數(shù)傳遞的對(duì)象。默認(rèn)實(shí)現(xiàn)是比較兩個(gè)對(duì)象的內(nèi)存地址(即它們是否為同一對(duì)象),但很多類重寫(xiě)此方法以提供有意義的相等性比較。
  • Object中的equals方法比較的是對(duì)象的地址是否相同;? equals方法可以被重寫(xiě),重寫(xiě)后equals方法比較的是兩個(gè)對(duì)象值是否相同。
  • Java規(guī)范中,對(duì)equals方法的使用必須遵循以下幾個(gè)規(guī)則:
    • 自反性:對(duì)于任何非空引用值XX.equals(X)都應(yīng)返回true;
    • 對(duì)稱性:對(duì)于任何非空引用值XY,當(dāng)且僅當(dāng) Y.equals(X)返回true時(shí), X.equals(Y)也應(yīng)該返回true;
    • 傳遞性:對(duì)于任何非空引用值X,Y,Z,如果X.equals(Y)返回true,并且Y.equals(Z)返回true,那么X.equals(Z)應(yīng)返回true;
    • 一致性:對(duì)于任何非空引用值XY,多次調(diào)用 X.equals(Y)始終返回true或始終返回false。
  • equals和 ==的區(qū)別
    • equals比較的是兩個(gè)對(duì)象值是否相等,如果沒(méi)有被重寫(xiě),比較的是對(duì)象的引用地址是否相同;
    • ==用于比較基本數(shù)據(jù)類型的值是否相等,或比較兩個(gè)對(duì)象的引用地址是否相等;

    • String? hello? =? new? String("hello");
      String? hello1? =? new? String("hello");
      System.out .println(hello.equals(hello1));    //重寫(xiě)了 ,比較的是值 ,輸出結(jié)果為true
      System.out .println(hello?== hello1);         //比較的是引用地址 ,輸出結(jié)果為false                            
      int? age? =? 10;
      int? age2? =? 10;                             //比較基本類型的值
      System.out.println(age? ==? age2);??????      //輸出為true 

?2. public int hashCode()

  • 返回調(diào)用對(duì)象的哈希碼值。默認(rèn)情況下,這個(gè)方法返回對(duì)象的內(nèi)存地址轉(zhuǎn)換成的整數(shù)值。重寫(xiě)equals()時(shí)通常也需要重寫(xiě)hashCode(),以便保持equals()true的兩個(gè)對(duì)象具有相同的哈希碼。

?3. public String toString()

  • 返回對(duì)象的字符串表示形式。Object類的默認(rèn)實(shí)現(xiàn)返回一個(gè)由類名,符號(hào)“@”以及對(duì)象哈希碼的無(wú)符號(hào)十六進(jìn)制表示組成的字符串。通常,類會(huì)重寫(xiě)這個(gè)方法,提供更有意義的信息。
  • 比如System.out.print(person)等價(jià)于System.out.print(person.toString());???? //默認(rèn)返回對(duì)象的地址
  • getClass().getName是返回對(duì)象的全類名,? Integer.toHexString(hashCode())是以16進(jìn)制無(wú)符號(hào)整數(shù)形式返回此哈希碼的字符串表示

    形式。

?4. public final native Class<?> getClass()

  • 返回運(yùn)行時(shí)類的Class對(duì)象。Class類的實(shí)例表示正在運(yùn)行的Java應(yīng)用程序中的類和接口。

?5. protected native Object clone() throws CloneNotSupportedException

  • 創(chuàng)建并返回調(diào)用該方法的對(duì)象的一個(gè)副本。
  • 對(duì)象的類必須實(shí)現(xiàn)Cloneable接口,否則拋出CloneNotSupportedException。
  • clone生成的新對(duì)象與原對(duì)象的關(guān)系,區(qū)別在于兩個(gè)對(duì)象間是否存在相同的引用或?qū)?yīng)的內(nèi)存地址是否存在共用情況;若存在,則為 淺復(fù)

    ?,否則為?深復(fù)制?,深復(fù)制時(shí)需要將共同關(guān)聯(lián)的引用也復(fù)制完全。

?6. public void finalize()

  • 當(dāng)垃圾收集器確定不存在對(duì)該對(duì)象的更多引用時(shí),由垃圾收集器在垃圾回收前調(diào)用此方法。子類可以重寫(xiě)finalize()以進(jìn)行清理工作(諸如釋放資源等)。

?7. protected void finalize() throws Throwable

  • 雖然標(biāo)記為protected,但這是對(duì)finalize()方法的解釋。從Java 9開(kāi)始,已經(jīng)不再推薦使用finalize()方法,取而代之的是使用CleanerPhantomReference這樣的替代方案。

?8. public final void wait()?throws InterruptedException

  • 導(dǎo)致當(dāng)前線程等待,直到另一個(gè)線程調(diào)用此對(duì)象的notify()方法或notifyAll()方法。
  • 調(diào)用wait方法的當(dāng)前線程一定要擁有對(duì)象的監(jiān)視器鎖。
  • wait方法會(huì)把當(dāng)前線程放在對(duì)應(yīng)的等待隊(duì)列中,在這個(gè)對(duì)象上的所有同步請(qǐng)求都不會(huì)得到響應(yīng)。線程調(diào)用將不會(huì)調(diào)用線程,線程一直處于休眠狀態(tài)。要注意的是,? wait方法把當(dāng)前線程放置到這個(gè)對(duì)象的等待隊(duì)列中,解鎖也僅僅是在這個(gè)對(duì)象上;當(dāng)前線程在等待過(guò)程中仍然持有其他對(duì)象的鎖。
  • 如果當(dāng)前線程被其他線程在當(dāng)前線程等待之前或正在等待時(shí)調(diào)用了interrupt()中斷了,那么就會(huì)拋出InterruptException異常。
  • 為什么wait方法一般要寫(xiě)在while循環(huán)里?
    • 在某個(gè)線程調(diào)用notify到等待線程被喚醒的過(guò)程中,有可能出現(xiàn)另一個(gè)線程得到了鎖并修改了條件使得條件不再滿足;只有某些等待 線程的條件滿足了,但通知線程調(diào)用了notifyAll有可能出現(xiàn)偽喚醒。
  • wait方法和sleep方法的區(qū)別?
    • wait方法屬于object類,當(dāng)調(diào)用wait方法時(shí),線程會(huì)放棄對(duì)象鎖,進(jìn)入等待此對(duì)象的等待鎖定池,只有針對(duì)此對(duì)象調(diào)用notify方法后 本線程才會(huì)進(jìn)入對(duì)象鎖定池,準(zhǔn)備獲取對(duì)象鎖進(jìn)入運(yùn)行狀態(tài)。
    • sleep方法屬于thread,sleep方法導(dǎo)致程序暫停執(zhí)行指定的時(shí)間,讓出CPU給其他線程,但是它的監(jiān)控狀態(tài)依然保持,當(dāng)指定的時(shí)間到了又會(huì)恢復(fù)運(yùn)行狀態(tài)。在調(diào)用sleep方法過(guò)程中,線程不會(huì)釋放對(duì)象鎖。

?9. public final native void notify()

  • 喚醒正在等待對(duì)象監(jiān)視器的單個(gè)線程。
  • 喚醒可能等待該對(duì)象的對(duì)象鎖的其他線程。由JVM(與優(yōu)先級(jí)無(wú)關(guān))隨機(jī)挑選一個(gè)處于wait狀態(tài)的線程。

  • 在調(diào)用notify()之前,線程必須獲取該對(duì)象的對(duì)象鎖,執(zhí)行完notify()方法后,不會(huì)馬上釋放鎖,直到退出synchronized代碼塊,當(dāng)前線程 才會(huì)釋放鎖;? notify一次只能隨機(jī)通知一個(gè)線程進(jìn)行喚醒。

?10. public final native void notifyAll()

  • 喚醒正在等待對(duì)象監(jiān)視器的所有線程。
  • 使所有正在等待池中等待同一個(gè)共享資源的全部線程從等待狀態(tài)退出,進(jìn)入可運(yùn)行狀態(tài),讓它們同時(shí)競(jìng)爭(zhēng)對(duì)象鎖,只有獲得鎖的線程才能進(jìn)

    入就緒狀態(tài)。

?11. public final void wait(long timeout) throws InterruptedException

  • 使當(dāng)前線程等待指定的毫秒數(shù),除非另一個(gè)線程調(diào)用notify()notifyAll(),或當(dāng)前線程被中斷。使用該方法時(shí),傳入的timeout參數(shù)是最大等待時(shí)間。如果timeout為0,則一直等待直到被通知或中斷。

?12. public final void wait(long timeout, int nanos) throws InterruptedException

  • 使當(dāng)前線程等待至多timeout毫秒加nanos納秒,除非另一個(gè)線程調(diào)用notify()notifyAll(),或當(dāng)前線程被中斷。這個(gè)方法允許更精細(xì)的控制等待的時(shí)間。

????????注意,在使用wait()notify()notifyAll()這幾個(gè)方法時(shí),必須在同步塊或同步方法中調(diào)用,這是因?yàn)樗鼈冃枰i定對(duì)象監(jiān)視器。

雖然Object類提供了這些基本方法,通常在實(shí)際開(kāi)發(fā)中會(huì)通過(guò)各種并發(fā)工具類(如java.util.concurrent包中的類)來(lái)處理線程同步和通知問(wèn)題,因?yàn)樗鼈兲峁┝烁痈呒?jí)、易于使用和更可靠的并發(fā)管理功能。

最后需要提醒的是,Object類的某些方法如finalize()已被標(biāo)記為過(guò)時(shí),因?yàn)樗赡軙?huì)導(dǎo)致程序性能問(wèn)題,并且不保證垃圾收集器會(huì)按時(shí)調(diào)用它。從Java 9開(kāi)始,finalize()方法被明確標(biāo)記為過(guò)時(shí)(deprecated),并推薦使用其他資源釋放機(jī)制,如try-with-resources語(yǔ)句來(lái)管理資源自動(dòng)關(guān)閉。

????????

二、HashMap原理,是否存在線程安全問(wèn)題

? ? HashMap?是 Java 中一種基于哈希表的?Map?接口的實(shí)現(xiàn)。它存儲(chǔ)的內(nèi)容是鍵值對(duì) (key-value?對(duì)),每個(gè)鍵映射到一個(gè)值。HashMap?允許使用 null 值和 null 鍵。

????????HashMap簡(jiǎn)單說(shuō)就是它根據(jù)鍵的hashCode值存儲(chǔ)數(shù)據(jù),?多數(shù)情況下可以直接定位到它的值,因?具有很快的訪問(wèn)速 度,但遍歷順序卻是不確定的。

????????HashMap基于哈希表,底層結(jié)構(gòu)由數(shù)組來(lái)實(shí)現(xiàn),添加到集合中的元素以“key--value”形式保存到數(shù)組中,在數(shù)組中key- -value被包裝成?個(gè)實(shí)體來(lái)處理---也就是上?Map接?中的Entry。

????????HashMap中, Entry[]保存了集合中所有的鍵值對(duì),當(dāng)我們需要快速存儲(chǔ)、獲取、刪除集合中的元素時(shí),?? HashMap會(huì) 根據(jù)hash算法來(lái)獲得“鍵值對(duì)”在數(shù)組中存在的位置,以來(lái)實(shí)現(xiàn)對(duì)應(yīng)的操作?法。

????????HashMap底層是采?數(shù)組來(lái)維護(hù)的.Entry靜態(tài)內(nèi)部類的數(shù)組

static class Node<K,V> implements Map.Entry<K,V> {
        final int hash;
        final K key;
        V value;
        Node<K,V> next;

        Node(int hash, K key, V value, Node<K,V> next) {
            this.hash = hash;
            this.key = key;
            this.value = value;
            this.next = next;
        }

        public final K getKey()        { return key; }
        public final V getValue()      { return value; }
        public final String toString() { return key + "=" + value; }

        public final int hashCode() {
            return Objects.hashCode(key) ^ Objects.hashCode(value);
        }

        public final V setValue(V newValue) {
            V oldValue = value;
            value = newValue;
            return oldValue;
        }

        public final boolean equals(Object o) {
            if (o == this)
                return true;
            if (o instanceof Map.Entry) {
                Map.Entry<?,?> e = (Map.Entry<?,?>)o;
                if (Objects.equals(key, e.getKey()) &&
                    Objects.equals(value, e.getValue()))
                    return true;
            }
            return false;
        }
    }

????????HashMap添加元素:將準(zhǔn)備增加到map中的對(duì)象與該位置上的對(duì)象進(jìn)??較(equals?法),如果相同,那么就將該位置上 的那個(gè)對(duì)象(Entry類型)的value值替換掉,否則沿著該Entry的鏈繼續(xù)重復(fù)上述過(guò)程,如果到鏈的最后任然沒(méi)有找到與此對(duì)象相同的對(duì)? 象,那么這個(gè)時(shí)候就會(huì)被增加到數(shù)組中,將數(shù)組中該位置上的那個(gè)Entry對(duì)象鏈到該對(duì)象的后?(先hashcode計(jì)算位置,如果找到相同 位置便替換值,找不到則重復(fù)hashcode計(jì)算,直到最后在添加到hashmap最后?;? )?

????????HashMap是基于哈希表的Map接?的?同步實(shí)現(xiàn),允許null鍵值,但不保證映射的順序 ;底層使?數(shù)組實(shí)現(xiàn),數(shù)組中的 每項(xiàng)是?個(gè)鏈表 ;存儲(chǔ)時(shí)根據(jù)key的hash算法來(lái)決定其存儲(chǔ)位置;數(shù)組擴(kuò)容需要重新計(jì)算擴(kuò)容后每個(gè)元素在數(shù)組中的位置? 很耗性能;

????????ConcurrentHashMapHashMap的線程安全實(shí)現(xiàn),允許多個(gè)修改操作同時(shí)進(jìn)?(使?了鎖分離技術(shù)),它使?了多個(gè)鎖來(lái)

控制對(duì)hash表的不同段進(jìn)?的修改,每個(gè)段其實(shí)就是?個(gè)?的hashtable,它們有??的鎖。使?了多個(gè)?hash表(段 Segment),允許多個(gè)讀操作并發(fā)進(jìn)?,讀操作并不需要鎖,因?yàn)樗腍ashEntry?乎是不可變的

????????

這是?HashMap?的一些主要原理和工作方式:

  1. 存儲(chǔ)結(jié)構(gòu)
    HashMap?在內(nèi)部使用一個(gè)數(shù)組來(lái)存儲(chǔ)數(shù)據(jù),這個(gè)數(shù)組又被稱為“桶”(Bucket)。每個(gè)桶是一個(gè)鏈表,鏈表的每一個(gè)節(jié)點(diǎn)是一個(gè)?Entry?對(duì)象,該對(duì)象包含鍵、值以及指向下一個(gè)?Entry?節(jié)點(diǎn)的引用。

  2. 哈希函數(shù)
    當(dāng)我們向?HashMap?中插入一個(gè)?key-value?對(duì)時(shí),它首先會(huì)使用哈希函數(shù)計(jì)算出鍵對(duì)象的哈希碼。HashMap?通過(guò)使用?key.hashCode()?方法來(lái)獲取哈希碼,然后通過(guò)內(nèi)部的哈希函數(shù)來(lái)轉(zhuǎn)換成數(shù)組索引。

  3. 沖突解決
    由于桶的數(shù)量有限,會(huì)發(fā)生不同鍵的哈希碼產(chǎn)生相同數(shù)組索引的情況,這稱為“哈希沖突”。HashMap?使用鏈表來(lái)解決沖突,所有哈希值相同的元素會(huì)被存儲(chǔ)在同一個(gè)桶的鏈表中。從 Java 8 開(kāi)始,當(dāng)同一個(gè)桶中的元素個(gè)數(shù)超過(guò)一定的閾值(默認(rèn)是鏈表長(zhǎng)度大于 8),鏈表會(huì)被轉(zhuǎn)換成紅黑樹(shù)以提高性能。

  4. 查找元素
    在需要獲取元素時(shí),HashMap?使用鍵對(duì)象的哈希碼來(lái)找到其在數(shù)組中的桶位,然后遍歷鏈表或紅黑樹(shù)(如果轉(zhuǎn)換成紅黑樹(shù)的話)來(lái)找到對(duì)應(yīng)的節(jié)點(diǎn)。

  5. 擴(kuò)容
    當(dāng)?HashMap?中的元素?cái)?shù)量達(dá)到數(shù)組大小和加載因子(load factor,默認(rèn)是 0.75)的乘積時(shí),HashMap?會(huì)進(jìn)行擴(kuò)容操作,即創(chuàng)建一個(gè)新的更大的數(shù)組,并將舊數(shù)組中的所有元素重新插入到新數(shù)組中。這個(gè)過(guò)程叫做“rehash”。

  6. 迭代
    HashMap?的迭代器(Iterator)遍歷時(shí)按照哈希桶的順序進(jìn)行,而不是按照鍵或值的排序順序。若在迭代過(guò)程中對(duì)?HashMap?結(jié)構(gòu)進(jìn)行修改,很可能會(huì)拋出?ConcurrentModificationException(快速失敗行為)。

HashMap?的這些特性使它成為一個(gè)在大多數(shù)情況下都有良好性能的鍵值存儲(chǔ)結(jié)構(gòu)。但是正確地了解和使用?HashMap?的原理對(duì)于避免性能問(wèn)題和正確地進(jìn)行內(nèi)存使用仍然非常重要。

????????

由于?HashMap?是非線程安全的,當(dāng)多個(gè)線程同時(shí)對(duì)其進(jìn)行修改時(shí),可能會(huì)出現(xiàn)幾種問(wèn)題。這些問(wèn)題不只限制于數(shù)據(jù)的不一致性,還可能引發(fā)程序的崩潰。以下是一些可能出現(xiàn)的具體問(wèn)題:

  1. 數(shù)據(jù)丟失
    當(dāng)兩個(gè)線程同時(shí)執(zhí)行?put?操作,它們可能計(jì)算出相同的存儲(chǔ)位置從而覆蓋對(duì)方的數(shù)據(jù),這將導(dǎo)致其中一個(gè)鍵值對(duì)丟失。

  2. 無(wú)限循環(huán)
    在 JDK 7 及之前版本的?HashMap?中,多線程環(huán)境下擴(kuò)容(rehashing)可以導(dǎo)致循環(huán)鏈表的出現(xiàn),這會(huì)導(dǎo)致?get?方法陷入無(wú)限循環(huán)。

  3. 數(shù)據(jù)不一致
    如果一個(gè)線程正在讀取,而另一個(gè)線程同時(shí)修改了數(shù)據(jù)結(jié)構(gòu),讀線程可能會(huì)看到部分更新的數(shù)據(jù),從而導(dǎo)致不可預(yù)料的結(jié)果。

  4. ConcurrentModificationException?異常
    當(dāng)一個(gè)線程迭代?HashMap?時(shí),如果另外一個(gè)線程修改了?HashMap?的結(jié)構(gòu)(添加或刪除任何元素),那么迭代器將快速失敗并拋出?ConcurrentModificationException。

  5. 內(nèi)存泄漏
    在并發(fā)環(huán)境下,由于線程修改的不同步可能導(dǎo)致某些?Entry?節(jié)點(diǎn)從未正確刪除,致使垃圾收集器無(wú)法回收這部分內(nèi)存,隨之產(chǎn)生內(nèi)存泄漏。

如果需要在多線程環(huán)境下使用?Map?結(jié)構(gòu)而又不想處理上述問(wèn)題,可以使用一些線程安全的替代方案,例如:

  • Collections.synchronizedMap(new HashMap<>():使用 Collections 工具為?HashMap?提供同步的包裝器,但是每個(gè)方法調(diào)用都是同步的,可能會(huì)導(dǎo)致不必要的性能損耗。
  • ConcurrentHashMap:一種線程安全且高效的?HashMap?替代實(shí)現(xiàn)。它利用分鎖機(jī)制提供更高的并發(fā)性,通常是多線程環(huán)境下?HashMap?的最佳選擇。

了解問(wèn)題和可能的解決方案,可以確保在多線程環(huán)境中有效地使用?HashMap,避免競(jìng)態(tài)條件和其他同步相關(guān)問(wèn)題。

????????

三、Java如何進(jìn)?線程同步

在 Java 中,線程同步是指多個(gè)線程訪問(wèn)共享資源時(shí),確保每個(gè)線程看到一致的內(nèi)存狀態(tài)且不會(huì)相互干擾的機(jī)制。為了防止線程間出現(xiàn)沖突,Java 提供了多種線程同步的機(jī)制。

  1. 同步方法?(Synchronized Methods):
    在方法聲明中加入?synchronized?關(guān)鍵字可以使該方法在同一時(shí)間內(nèi)只能被一個(gè)線程訪問(wèn)。當(dāng)一個(gè)線程訪問(wèn)一個(gè)對(duì)象的?synchronized?方法時(shí),其他試圖訪問(wèn)該對(duì)象的?synchronized?方法的線程將會(huì)阻塞。

    public synchronized void method() {
        // 同步代碼
    }
  2. 同步塊?(Synchronized Blocks):
    如果只有方法中的某個(gè)代碼塊需要同步,可以使用?synchronized?關(guān)鍵字來(lái)同步一個(gè)代碼塊,這比同步整個(gè)方法更加細(xì)粒度,可以減少等待時(shí)間,從而提高性能。

    public void method() {
        // ... 非同步代碼
        synchronized(this) { // this 是鎖定的對(duì)象,也可以是其他對(duì)象
            // 同步代碼
        }
        // ... 非同步代碼
    }
  3. ?(Locks):
    Java?java.util.concurrent.locks?包提供了更加靈活的鎖定機(jī)制。其中?ReentrantLock?是常用的實(shí)現(xiàn),它具有與使用關(guān)鍵字?synchronized?類似的基本行為和語(yǔ)義,但擁有額外的功能。

    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class Counter {
        private final Lock lock = new ReentrantLock();
        private int count = 0;
        
        public void increment() {
            lock.lock();
            try {
                count++;
            } finally {
                // 確保在發(fā)生異常時(shí)鎖能被釋放
                lock.unlock();
            }
        }
    }
  4. 原子變量
    java.util.concurrent.atomic?包提供了一組原子類,例如?AtomicInteger,?AtomicLong,?AtomicReference?等。這些類利用底層硬件的原子指令來(lái)實(shí)現(xiàn)同步,而無(wú)需使用傳統(tǒng)的鎖機(jī)制。這些操作是非阻塞的,并且往往是性能更高的選項(xiàng)。

    import java.util.concurrent.atomic.AtomicInteger;
    
    public class Counter {
        private AtomicInteger count = new AtomicInteger(0);
        
        public void increment() {
            count.incrementAndGet();
        }
        
        public int getValue() {
            return count.get();
        }
    }
  5. volatile 關(guān)鍵字
    當(dāng)一個(gè)變量被聲明為?volatile,那么線程每次讀取變量時(shí)都會(huì)從內(nèi)存中讀,每次寫(xiě)回變量時(shí)都會(huì)寫(xiě)入到內(nèi)存中。這確保了該變量的可見(jiàn)性,即當(dāng)一個(gè)線程更新了該變量時(shí),其他線程能立刻看到修改后的值。

    public class SharedObject {
        private volatile int sharedVariable = 0;
        
        public void increment() {
            sharedVariable++;
        }
        
        public int getSharedVariable() {
            return sharedVariable;
        }
    }

????????請(qǐng)注意,volatile?不能保證復(fù)合操作(如自增)的原子性,它僅保證變量的讀寫(xiě)操作的可見(jiàn)性。

使用哪種同步機(jī)制取決于具體的情況,正確的選擇可以提供良好的性能同時(shí)確保線程安全。對(duì)于一些高級(jí)的同步需要,我們可能還需要使用到?Semaphore,?CountDownLatch,?CyclicBarrier,?Phaser?等同步工具,它們?cè)?java.util.concurrent?包下提供了更為復(fù)雜的并發(fā)控制。

????????

四、CAS原理

CAS(Compare-And-Swap 或 Compare-And-Set)是一種用于實(shí)現(xiàn)多線程同步的技術(shù)。它涉及對(duì)內(nèi)存中的某些值進(jìn)行原子地比較和更新。"原子"指的是操作作為一個(gè)不可分割的單元執(zhí)行,要么完全執(zhí)行,要么完全不執(zhí)行,不會(huì)出現(xiàn)中間狀態(tài)。

CAS 操作通常包括以下三個(gè)操作數(shù):

  1. 內(nèi)存位置(V):要操作的內(nèi)存地址。
  2. 期望原值(A):期望讀到的值。
  3. 新值(B):若期望原值驗(yàn)證為真,即內(nèi)存位置的值與期望原值相等,則更新為此新值。

這個(gè)操作的偽代碼可以表示為:

if memory_value == expected_value
    memory_value = new_value
else
    handle the failure (do nothing or retry or abort, etc.)

執(zhí)行 CAS 操作的基本步驟是:

  1. 系統(tǒng)從內(nèi)存地址 V 讀取當(dāng)前值。
  2. 檢查當(dāng)前值是否與期望原值 A 相等。
  3. 如果相等,則將新值 B 更新到內(nèi)存地址 V。
  4. 如果不等,則不做任何操作或者采取其他補(bǔ)救措施(比如重試或回滾)。

CAS 操作是無(wú)鎖編程中常用的技術(shù),有助于在不使用傳統(tǒng)鎖機(jī)制的情況下實(shí)現(xiàn)對(duì)共享數(shù)據(jù)的安全操作。在多處理器系統(tǒng)中,CAS 是通過(guò)硬件指令直接支持的,因此可以高效地執(zhí)行。

CAS 有以下優(yōu)點(diǎn):

  • 性能:由于不需要鎖定,CAS 可以減少線程上下文切換的成本,通常比使用鎖更高效。
  • 死鎖避免:既然沒(méi)有使用傳統(tǒng)的鎖,也就不可能出現(xiàn)死鎖的情況。

不過(guò),CAS 也存在一些問(wèn)題:

  • ABA 問(wèn)題:如果值從 A 變成 B,然后又變回 A,CAS 會(huì)認(rèn)為什么都沒(méi)有改變,然而實(shí)際上可能發(fā)生了重要的變動(dòng)。
  • 循環(huán)時(shí)間長(zhǎng):如果很多線程同時(shí)嘗試進(jìn)行 CAS,那么只有一個(gè)能成功,其他線程可能不得不多次嘗試。
  • 只能保證一個(gè)共享變量的原子操作:如果需要同時(shí)更新多個(gè)共享變量,則不能直接使用 CAS。

總的來(lái)說(shuō),CAS 是一種基于硬件實(shí)現(xiàn)的輕量級(jí)同步機(jī)制,適用于某些不需要嚴(yán)格的鎖定機(jī)制就能解決的線程安全問(wèn)題。它是 Java 中?java.util.concurrent.atomic?包中的原子變量類的關(guān)鍵實(shí)現(xiàn)技術(shù)。

????????

五、JVM垃圾回收之GC算法有哪些

Java 虛擬機(jī)(JVM)使用垃圾回收(GC)算法來(lái)管理和回收不再使用的內(nèi)存。主要的垃圾回收算法包括:

  1. 標(biāo)記-清除(Mark-Sweep)算法

    • 標(biāo)記:該階段標(biāo)記出所有從根集合開(kāi)始可達(dá)的對(duì)象。
    • 清除:回收所有未被標(biāo)記的對(duì)象占用的內(nèi)存。
      缺點(diǎn)是兩個(gè)主要方面:標(biāo)記和清除過(guò)程的效率不高,以及清除后容易產(chǎn)生內(nèi)存碎片。
  2. 復(fù)制(Copy or Scavenge)算法

    • 將內(nèi)存分為兩個(gè)相等的區(qū)域,每次只使用其中的一個(gè)。
    • 當(dāng)進(jìn)行垃圾回收時(shí),將正在使用的內(nèi)存區(qū)域中存活的對(duì)象復(fù)制到未使用的區(qū)域,然后清除正在使用的內(nèi)存區(qū)域中的所有對(duì)象。
    • 優(yōu)點(diǎn)是避免了內(nèi)存碎片,缺點(diǎn)是內(nèi)存利用效率為 50%。
  3. 標(biāo)記-整理(Mark-Compact)算法

    • 結(jié)合了“標(biāo)記-清除”和“復(fù)制”算法的優(yōu)點(diǎn)。
    • 標(biāo)記:和標(biāo)記-清除算法一樣進(jìn)行標(biāo)記。
    • 整理:將所有存活的對(duì)象壓縮到內(nèi)存的一端,清理掉端邊界外的內(nèi)存。
      優(yōu)點(diǎn)是解決內(nèi)存碎片問(wèn)題而不需要犧牲過(guò)多的內(nèi)存。
  4. 增量(Incremental)垃圾回收

    • 讓垃圾回收分批進(jìn)行,不是一次性清理完所有垃圾。
    • 目的是減少每次垃圾回收的時(shí)間,使得垃圾回收對(duì)系統(tǒng)的影響更為平滑。
  5. 分代收集(Generational Collection)算法

    • 根據(jù)對(duì)象存活周期的不同,將內(nèi)存劃分為新生代(Young Generation)、老年代(Old Generation)和永久代(Permanent Generation,但在 Java 8 中已經(jīng)被移除,改成了元空間(MetaSpace))。
    • 新生代使用復(fù)制算法,老年代一般采用標(biāo)記-清除或標(biāo)記-整理算法。
  6. 并行(Parallel)垃圾回收

    • 使用多個(gè)垃圾回收線程并行執(zhí)行垃圾回收,以提高垃圾回收的效率。
    • 適用于多核處理器,能夠更高效地進(jìn)行垃圾回收。
  7. 并發(fā)(Concurrent)垃圾回收

    • 允許垃圾回收線程與應(yīng)用程序線程同時(shí)工作。
    • 旨在減少應(yīng)用程序的停頓時(shí)間,適合需要響應(yīng)時(shí)間快的應(yīng)用。

JVM 中有不同的垃圾回收器實(shí)現(xiàn)上述算法。常見(jiàn)的垃圾回收器有:

  • Serial GC:?jiǎn)尉€程運(yùn)行,采用標(biāo)記-復(fù)制算法,適合單核處理器或小內(nèi)存環(huán)境。
  • Parallel GC (也稱為吞吐量收集器):多線程執(zhí)行,側(cè)重增加吞吐量。
  • CMS (Concurrent Mark-Sweep) GC:以獲取最短停頓時(shí)間為目標(biāo),使用并發(fā)標(biāo)記清除算法。
  • G1 (Garbage-First) GC:旨在為多核機(jī)器提供高吞吐量和低延遲的性能表現(xiàn),適用于大內(nèi)存。

與這些收集器相關(guān)的具體細(xì)節(jié)和性能特征,取決于 JVM 的實(shí)現(xiàn)和版本。在 OpenJDK 和 Oracle JDK 9 及以后的版本中,還提供了新的垃圾回收器(如 ZGC 和 Shenandoah),旨在降低停頓時(shí)間,同時(shí)適應(yīng)大內(nèi)存和多處理器環(huán)境。

????????

六、Mysql索引原理以及查詢優(yōu)化

MySQL索引是幫助MySQL高效獲取數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu)。以下是一些基本的MySQL索引類型和它們的工作原理:

  1. B+Tree索引:最常用的索引類型,適合用于全鍵值、鍵值范圍或鍵值前綴查找。B-Tree索引能夠加速數(shù)據(jù)的讀取,但會(huì)額外消耗一些空間來(lái)存儲(chǔ)索引,并且在插入、更新和刪除時(shí)需要同步更新索引。

  2. 哈希索引:基于哈希表的實(shí)現(xiàn),適合等值查詢,不適合范圍查詢和部分鍵匹配查詢。主要優(yōu)點(diǎn)是查找速度快,缺點(diǎn)是不支持排序和分組。

  3. 全文索引?(Fulltext Indexes):特別適用于對(duì)文本內(nèi)容進(jìn)行搜索的應(yīng)用,可以快速定位包含某個(gè)詞或短語(yǔ)的記錄。

  4. 空間數(shù)據(jù)索引?(R-Tree):用于空間數(shù)據(jù)類型,如GIS數(shù)據(jù)。

工作原理:

  • B+Tree索引:通過(guò)維護(hù)一個(gè)平衡搜索樹(shù)來(lái)進(jìn)行優(yōu)化檢索,數(shù)據(jù)按照順序存儲(chǔ),可用于查找、排序和分組操作。

查詢優(yōu)化:

  • 選擇正確的索引:了解不同類型的查詢和哪些情況下最適合使用索引。找出查詢中常用的列并為它們建立索引。
  • 索引列上進(jìn)行操作:避免在索引列上做運(yùn)算或使用函數(shù),這將導(dǎo)致無(wú)法使用索引。
  • 使用最左前綴法則:對(duì)于復(fù)合索引,確保查詢條件與索引中列的順序一致。
  • 避免全表掃描:盡量使用索引來(lái)避免全表掃描,適當(dāng)?shù)叵拗撇樵兎祷氐男袛?shù)。
  • 索引的選擇性:選擇性是不重復(fù)的索引值與數(shù)據(jù)表中的記錄數(shù)的比例,選擇性越高的索引性能越好。
  • 使用Explain來(lái)分析查詢:使用EXPLAIN語(yǔ)句來(lái)分析你的查詢以及索引使用情況,可以幫助發(fā)現(xiàn)性能瓶頸。
  • 適當(dāng)?shù)腖ike語(yǔ)句:當(dāng)必須使用LIKE查詢時(shí),如果模式以通配符開(kāi)頭,索引將不會(huì)被使用。盡可能避免'%value%'這種模式,而使用'value%'

????????確保定期維護(hù)索引以防止索引碎片,導(dǎo)致查詢效率下降。通過(guò)定期運(yùn)行OPTIMIZE TABLE命令,可以幫助重新組織存儲(chǔ)和重新構(gòu)建數(shù)據(jù)庫(kù)索引,進(jìn)而提高查詢效率。

????????

七、TCP擁塞控制

TCP擁塞控制是一種網(wǎng)絡(luò)機(jī)制,它旨在防止過(guò)多的數(shù)據(jù)同時(shí)注入網(wǎng)絡(luò),從而避免網(wǎng)絡(luò)中的路由器或鏈路過(guò)載,導(dǎo)致過(guò)度的延遲或丟包。TCP的擁塞控制通過(guò)動(dòng)態(tài)調(diào)整各TCP連接的發(fā)送窗口大小來(lái)控制它們各自的發(fā)送速率。

以下是TCP擁塞控制的主要算法:

?1. 慢啟動(dòng)(Slow Start)

  • TCP連接開(kāi)始時(shí),擁塞窗口(cwnd)從一個(gè)很小的值(通常是一個(gè)MSS,即最大報(bào)文段大?。╅_(kāi)始增長(zhǎng),每當(dāng)收到一個(gè)ACK,cwnd就增加一個(gè)MSS,這樣,cwnd每個(gè)RTT(往返時(shí)間)就翻倍增長(zhǎng),呈指數(shù)增長(zhǎng)。
  • 當(dāng)cwnd達(dá)到慢啟動(dòng)閾值(ssthresh)時(shí),TCP切換到擁塞避免算法。

?2. 擁塞避免(Congestion Avoidance)

  • 這個(gè)階段TCP轉(zhuǎn)變?yōu)楦€(wěn)健的增長(zhǎng)方式,每個(gè)RTT只增加一個(gè)MSS,呈線性增長(zhǎng),以穩(wěn)步增加網(wǎng)絡(luò)負(fù)載。
  • 如果出現(xiàn)丟包(如超時(shí)或接收到重復(fù)ACKs),TCP認(rèn)為網(wǎng)絡(luò)出現(xiàn)擁塞,并且將ssthresh設(shè)置為當(dāng)前cwnd的一半,并進(jìn)入快速恢復(fù)或慢啟動(dòng)。

?3. 快速重傳(Fast Retransmit)

  • 如果發(fā)送端收到三個(gè)重復(fù)的ACK,它就知道該段后面的報(bào)文段一定是丟失了,而不是需要等待定時(shí)器超時(shí)。
  • 它會(huì)立即重傳這個(gè)失序的報(bào)文段而不是等待超時(shí),同時(shí)不減小cwnd的大小以避免降低傳輸速率。

?4. 快速恢復(fù)(Fast Recovery)

  • 在執(zhí)行快速重傳之后,TCP進(jìn)入快速恢復(fù)階段,ssthresh被設(shè)置為當(dāng)前cwnd的一半,cwnd被設(shè)置為ssthresh加3倍MSS(對(duì)于之前接收的三個(gè)重復(fù)ACK),然后每接收一個(gè)重復(fù)的ACK就增加一個(gè)MSS。
  • 當(dāng)終于收到了一個(gè)新的ACK,認(rèn)為網(wǎng)絡(luò)恢復(fù)了,cwnd被重新設(shè)置為ssthresh的值,TCP進(jìn)入擁塞避免階段。

?5. 超時(shí)處理

  • 如果等待ACK的時(shí)間超過(guò)了預(yù)定的超時(shí)時(shí)間,TCP認(rèn)為發(fā)生了嚴(yán)重的擁塞,并將ssthresh設(shè)置為當(dāng)前cwnd的一半,并且將cwnd重新設(shè)置為1MSS,然后進(jìn)入慢啟動(dòng)階段。

????????隨著時(shí)間的推移,TCP的擁塞控制算法也不斷發(fā)展和完善,例如引入了更為復(fù)雜的算法如BBR(Bottleneck Bandwidth and RTT)等,旨在進(jìn)一步優(yōu)化性能。

????????TCP擁塞控制的工作原理是一個(gè)動(dòng)態(tài)的過(guò)程,它需要根據(jù)網(wǎng)絡(luò)的實(shí)時(shí)狀態(tài)不斷地調(diào)整發(fā)送速率。這些機(jī)制使得TCP能夠動(dòng)態(tài)適應(yīng)不同的網(wǎng)絡(luò)擁塞情況,能夠在各種類型的網(wǎng)絡(luò)中有效地傳輸數(shù)據(jù),同時(shí)又不會(huì)因?yàn)檫^(guò)多的數(shù)據(jù)流量而導(dǎo)致網(wǎng)絡(luò)崩潰。

????????

八、算法:? 給定—棵二叉樹(shù),找到這棵樹(shù)最中最后—行中最左邊的值

????????為了在Java中實(shí)現(xiàn)這個(gè)算法,您可以創(chuàng)建一個(gè)TreeNode類表示二叉樹(shù)節(jié)點(diǎn),然后使用廣度優(yōu)先搜索(BFS)遍歷整棵樹(shù)。通過(guò)隊(duì)列來(lái)實(shí)現(xiàn)BFS算法,您可以輕松地按層遍歷二叉樹(shù),并記錄下每層的第一個(gè)節(jié)點(diǎn)。

????????以下是一個(gè)實(shí)現(xiàn)這一功能的Java代碼示例:

import java.util.Queue;
import java.util.LinkedList;

class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
    
    TreeNode(int x) {
        val = x;
    }
}

public class BinaryTreeBottomLeftValue {
    public int findBottomLeftValue(TreeNode root) {
        if (root == null) return -1;
        
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(root);
        int result = root.val;  // 初始化結(jié)果為根節(jié)點(diǎn)的值
        
        while (!queue.isEmpty()) {
            int size = queue.size();  // 當(dāng)前層的節(jié)點(diǎn)數(shù)量
            for (int i = 0; i < size; i++) {
                TreeNode node = queue.poll();
                // 如果是當(dāng)前層的第一個(gè)節(jié)點(diǎn),更新結(jié)果值
                if (i == 0) result = node.val;
                // 添加子節(jié)點(diǎn)到隊(duì)列
                if (node.left != null) queue.add(node.left);
                if (node.right != null) queue.add(node.right);
            }
        }
        
        return result;  // 返回最后一行最左邊的值
    }
    
    public static void main(String[] args) {
        // 示例二叉樹(shù)
        //            1
        //           / \
        //          2   3
        //         /   / \
        //        4   5   6
        //           /
        //          7

        // 示例二叉樹(shù)構(gòu)建
        TreeNode root = new TreeNode(1);
        root.left = new TreeNode(2);
        root.right = new TreeNode(3);
        root.left.left = new TreeNode(4);
        root.right.left = new TreeNode(5);
        root.right.right = new TreeNode(6);
        root.right.left.left = new TreeNode(7);
        
        BinaryTreeBottomLeftValue solution = new BinaryTreeBottomLeftValue();
        int bottomLeft = solution.findBottomLeftValue(root);
        System.out.println("Bottom left value: " + bottomLeft);  // 應(yīng)輸出 7
    }
}

在這個(gè)Java程序中,我們定義了TreeNode類來(lái)表示樹(shù)的節(jié)點(diǎn),然后在BinaryTreeBottomLeftValue類中添加了findBottomLeftValue方法。這個(gè)方法使用隊(duì)列來(lái)追蹤需要訪問(wèn)的節(jié)點(diǎn),遍歷所有層,并記錄下每一層中的第一個(gè)節(jié)點(diǎn)值。最終,返回的就是最后一行中最左邊的值。

main方法中,我們建立了一個(gè)示例二叉樹(shù),并調(diào)用findBottomLeftValue方法來(lái)獲取最后一行最左邊的值。

????????

(二面題,考察代碼能力。60分鐘)

九、知道什么設(shè)計(jì)模式,分別介紹

????????設(shè)計(jì)模式是解決軟件設(shè)計(jì)中常見(jiàn)問(wèn)題的通用、可重用的解決方案。設(shè)計(jì)模式可以分為三個(gè)主要類別:創(chuàng)建型、結(jié)構(gòu)型和行為型。下面是每一類中一些常用的設(shè)計(jì)模式及其簡(jiǎn)要介紹:

????????

創(chuàng)建型模式

創(chuàng)建型模式專注于如何創(chuàng)建對(duì)象或類的實(shí)例。

  1. 工廠方法模式(Factory Method):
    允許接口定義創(chuàng)建對(duì)象的方法,但由子類決定要實(shí)例化的類的類型。工廠方法將對(duì)象的創(chuàng)建延遲到子類。

  2. 抽象工廠模式(Abstract Factory):
    提供一個(gè)接口用于創(chuàng)建相關(guān)或依賴對(duì)象的家族,而不需要明確指定具體類。

  3. 建造者模式(Builder):
    分離復(fù)雜對(duì)象的構(gòu)建和表示,同樣的構(gòu)建過(guò)程可以創(chuàng)建不同的表示。

  4. 原型模式(Prototype):
    通過(guò)拷貝一個(gè)現(xiàn)有對(duì)象的方式來(lái)創(chuàng)建對(duì)象,而不是通過(guò)實(shí)例化。

  5. 單例模式(Singleton):
    確保一個(gè)類僅有一個(gè)實(shí)例,并提供一個(gè)全局訪問(wèn)點(diǎn)。

????????

結(jié)構(gòu)型模式

結(jié)構(gòu)型模式與類和對(duì)象的組織有關(guān),它們定義了類之間的關(guān)系來(lái)實(shí)現(xiàn)更大的功能。

  1. 適配器模式(Adapter):
    允許將不兼容的接口轉(zhuǎn)換為其他類可以工作的接口。

  2. 橋接模式(Bridge):
    分離抽象部分和實(shí)現(xiàn)部分,使它們可以獨(dú)立變化。

  3. 組合模式(Composite):
    允許將對(duì)象組成樹(shù)形結(jié)構(gòu)來(lái)表示“部分-整體”的層次結(jié)構(gòu)。使得用戶對(duì)單個(gè)對(duì)象和組合對(duì)象的使用具有一致性。

  4. 裝飾器模式(Decorator):
    向一個(gè)現(xiàn)有的對(duì)象添加新的功能,同時(shí)又不改變其結(jié)構(gòu)。

  5. 外觀模式(Facade):
    提供了一個(gè)統(tǒng)一的接口,用來(lái)訪問(wèn)子系統(tǒng)中的一群接口。外觀定義了一個(gè)高層接口,讓子系統(tǒng)更容易使用。

  6. 享元模式(Flyweight):
    運(yùn)用共享技術(shù)有效地支持大量細(xì)粒度的對(duì)象。

  7. 代理模式(Proxy):
    為其他對(duì)象提供一種代理以控制對(duì)這個(gè)對(duì)象的訪問(wèn)。

????????

行為型模式

行為型模式專注于算法和對(duì)象間職責(zé)的分配。

  1. 責(zé)任鏈模式(Chain of Responsibility):
    為請(qǐng)求創(chuàng)建一個(gè)接收者對(duì)象的鏈。這種模式給更多的對(duì)象一個(gè)機(jī)會(huì)處理請(qǐng)求。

  2. 命令模式(Command):
    將請(qǐng)求封裝為一個(gè)對(duì)象,從而允許我們使用不同的請(qǐng)求、隊(duì)列請(qǐng)求、記錄日志等來(lái)參數(shù)化其他對(duì)象。

  3. 解釋器模式(Interpreter):
    定義一種語(yǔ)法用于一個(gè)某個(gè)特定類型的問(wèn)題,并提供該語(yǔ)法的解釋器。

  4. 迭代器模式(Iterator):
    提供一種方法順序訪問(wèn)一個(gè)聚合對(duì)象中各個(gè)元素,而又不暴露該對(duì)象的內(nèi)部表示。

  5. 中介者模式(Mediator):
    封裝多個(gè)對(duì)象之間復(fù)雜的交互和協(xié)作關(guān)系,中介者通過(guò)減少類之間的通信線條數(shù)量,來(lái)減少依賴性。

  6. 備忘錄模式(Memento):
    在不破壞封裝的前提下,捕獲并保存一個(gè)對(duì)象的內(nèi)部狀態(tài),以便在以后可以恢復(fù)到這個(gè)狀態(tài)。

  7. 觀察者模式(Observer):
    一種訂閱機(jī)制,當(dāng)一個(gè)對(duì)象狀態(tài)變化時(shí),所有依賴它的對(duì)象都會(huì)收到通知并自動(dòng)更新。

  8. 狀態(tài)模式(State):
    允許一個(gè)對(duì)象在其內(nèi)部狀態(tài)改變時(shí)改變它的行為。

  9. 策略模式(Strategy):
    定義一系列算法,并將每一個(gè)算法封裝起來(lái),使他們可以互相替換。

  10. 模板方法模式(Template Method):
    定義算法的框架,允許子類在不改變算法結(jié)構(gòu)的情況下,重寫(xiě)算法的某些步驟。

  11. 訪問(wèn)者模式(Visitor):
    對(duì)于一個(gè)對(duì)象結(jié)構(gòu)中的元素,允許一個(gè)外部的訪問(wèn)者來(lái)訪問(wèn),無(wú)需改變對(duì)象結(jié)構(gòu)的具體元素類。

這些設(shè)計(jì)模式在軟件開(kāi)發(fā)中被廣泛應(yīng)用,能夠幫助開(kāi)發(fā)者通過(guò)事先定義好的、經(jīng)過(guò)實(shí)戰(zhàn)考驗(yàn)的方法來(lái)解決各種設(shè)計(jì)問(wèn)題,從而編寫(xiě)出更加可維護(hù)、更加清晰、更加可靠的代碼。

? ? ? ? 詳解設(shè)計(jì)模式專欄:(后續(xù)慢慢更新)

????????

十、算法:求?序數(shù)組中第k?的數(shù)

????????要在無(wú)序數(shù)組中找到第k大的數(shù),可以使用快速選擇(Quickselect)算法。該算法的思想是基于快速排序的分治思想,但是只執(zhí)行必要的分區(qū)操作,從而更高效地找到第k大的數(shù)。

????????下面是使用Java實(shí)現(xiàn)快速選擇算法來(lái)找到無(wú)序數(shù)組中第k大的數(shù)的示例代碼:

import java.util.Random;

public class QuickSelect {
    private static Random random = new Random();

    public static int findKthLargest(int[] nums, int k) {
        return quickSelect(nums, 0, nums.length - 1, nums.length - k);
    }

    private static int quickSelect(int[] nums, int start, int end, int k) {
        if (start == end) {
            return nums[start];
        }

        int pivotIndex = partition(nums, start, end);

        if (pivotIndex == k) {
            return nums[pivotIndex];
        } else if (pivotIndex < k) {
            return quickSelect(nums, pivotIndex + 1, end, k);
        } else {
            return quickSelect(nums, start, pivotIndex - 1, k);
        }
    }

    private static int partition(int[] nums, int start, int end) {
      // 隨機(jī)選擇一個(gè)pivot
        int randomIndex = start + random.nextInt(end - start + 1);
        swap(nums, randomIndex, end);

        int pivot = nums[end];
        int pivotIndex = start;

        for (int i = start; i < end; i++) {
            if (nums[i] < pivot) {
                swap(nums, i, pivotIndex);
                pivotIndex++;
            }
        }

        swap(nums, pivotIndex, end);
        return pivotIndex;
    }

    private static void swap(int[] nums, int i, int j) {
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }

    public static void main(String[] args) {
        int[] nums = {3, 5, 2, 1, 6, 4};
        int k = 2;

        int result = findKthLargest(nums, k);
        System.out.println("第" + k + "大的數(shù)是: " + result);
    }
}

????????在示例代碼中,findKthLargest方法接受一個(gè)無(wú)序數(shù)組和一個(gè)整數(shù)k作為輸入,返回第k大的數(shù)。quickSelect方法是實(shí)現(xiàn)快速選擇的遞歸函數(shù),用于分區(qū)和選擇。partition方法根據(jù)選定的pivot元素將數(shù)組分成兩部分,并返回pivot的索引。

????????在示例代碼的main方法中,我們提供了一個(gè)無(wú)序數(shù)組和一個(gè)k值進(jìn)行測(cè)試,并打印出結(jié)果。

????????需要注意的是,上述代碼的示例是找無(wú)序數(shù)組中第k大的數(shù)。如果要找第k小的數(shù),只需修改遞歸調(diào)用的條件和相應(yīng)返回的數(shù)值即可。

????????快速選擇算法的時(shí)間復(fù)雜度為O(N),其中N是數(shù)組的長(zhǎng)度。

????????

十一、算法:求旋轉(zhuǎn)數(shù)組找最?值(?分法)

????????求解旋轉(zhuǎn)數(shù)組中最小值的問(wèn)題可以使用二分法進(jìn)行高效求解。旋轉(zhuǎn)數(shù)組是指將一個(gè)升序排列的數(shù)組的前若干個(gè)元素搬到數(shù)組末尾而得到的數(shù)組。

????????下面是使用Java實(shí)現(xiàn)二分法求解旋轉(zhuǎn)數(shù)組中最小值的示例代碼:

public class MinimumInRotatedArray {
    public static int findMin(int[] nums) {
        int left = 0;
        int right = nums.length - 1;

        while (left < right) {
            int mid = left + (right - left) / 2;

            if (nums[mid] > nums[right]) {
                left = mid + 1;
            } else if (nums[mid] < nums[right]) {
                right = mid;
            } else {
                right--;
            }
        }

        return nums[left];
    }

    public static void main(String[] args) {
        int[] nums = {4, 5, 6, 7, 0, 1, 2};

        int min = findMin(nums);
        System.out.println("旋轉(zhuǎn)數(shù)組中的最小值是: " + min);
    }
}

????????在示例代碼中,findMin方法接受一個(gè)旋轉(zhuǎn)數(shù)組作為輸入,并使用二分法來(lái)搜索旋轉(zhuǎn)數(shù)組中的最小值。算法首先初始化左右兩個(gè)指針,指向數(shù)組的第一個(gè)和最后一個(gè)元素。然后,通過(guò)計(jì)算中間元素的索引,將問(wèn)題的規(guī)??s小為子數(shù)組。在每一次迭代中,比較中間元素和最右側(cè)元素的大小關(guān)系,根據(jù)比較結(jié)果調(diào)整左右指針的位置,直到最小值被找到。

????????在示例代碼的main方法中,我們提供了一個(gè)旋轉(zhuǎn)數(shù)組進(jìn)行測(cè)試,并打印出最小值。

????????該算法的時(shí)間復(fù)雜度為O(logN),其中N是旋轉(zhuǎn)數(shù)組的長(zhǎng)度。二分法的每一次迭代都將問(wèn)題的規(guī)模減半,因此算法的時(shí)間復(fù)雜度是對(duì)數(shù)級(jí)別的。

????????

十二、算法:判斷?叉樹(shù)是否鏡像(遞歸)

????????判斷二叉樹(shù)是否鏡像可以使用遞歸的方式來(lái)解決。對(duì)于兩棵樹(shù)是鏡像的,意味著它們的根節(jié)點(diǎn)的值相同,并且每個(gè)樹(shù)的右子樹(shù)都與另一個(gè)樹(shù)的左子樹(shù)鏡像對(duì)稱。

????????下面是使用Java遞歸實(shí)現(xiàn)判斷二叉樹(shù)是否鏡像的示例代碼:

class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;

    TreeNode(int val) {
        this.val = val;
    }
}

public class MirrorBinaryTree {
    public static boolean isMirror(TreeNode root) {
        if (root == null) {
            return true;
        }

        return isSymmetric(root.left, root.right);
    }

    private static boolean isSymmetric(TreeNode left, TreeNode right) {
        if (left == null && right == null) {
            return true;
        }

        if (left == null || right == null || left.val != right.val) {
            return false;
        }

        return isSymmetric(left.left, right.right) && isSymmetric(left.right, right.left);
    }

    public static void main(String[] args) {
        TreeNode root = new TreeNode(1);
        root.left = new TreeNode(2);
        root.right = new TreeNode(2);
        root.left.left = new TreeNode(3);
        root.left.right = new TreeNode(4);
        root.right.left = new TreeNode(4);
        root.right.right = new TreeNode(3);

        boolean result = isMirror(root);
        System.out.println("二叉樹(shù)是否鏡像: " + result);
    }
}

????????在示例代碼中,isMirror方法接受一個(gè)二叉樹(shù)的根節(jié)點(diǎn)作為輸入,使用遞歸判斷二叉樹(shù)是否鏡像。在isSymmetric方法中,首先判斷左右子樹(shù)是否都為空,如果是,則表示當(dāng)前節(jié)點(diǎn)及其子樹(shù)鏡像對(duì)稱。其次,判斷左右子樹(shù)是否都不為空,并且當(dāng)前節(jié)點(diǎn)的值相同,如果是,則遞歸判斷左子樹(shù)的左子樹(shù)和右子樹(shù)的右子樹(shù),以及左子樹(shù)的右子樹(shù)和右子樹(shù)的左子樹(shù)是否鏡像對(duì)稱。最后,如果上述條件都不滿足,則表示二叉樹(shù)不是鏡像。

????????在示例代碼的main方法中,我們構(gòu)建了一個(gè)鏡像二叉樹(shù)進(jìn)行測(cè)試,并打印出結(jié)果。

????????如果二叉樹(shù)為空,也可視為空鏡像,因此在isMirror方法中增加了對(duì)空樹(shù)的處理。

????????該算法的時(shí)間復(fù)雜度為O(N),其中N是二叉樹(shù)中的節(jié)點(diǎn)數(shù)量。因?yàn)樗惴ㄐ枰闅v每個(gè)節(jié)點(diǎn)且只訪問(wèn)一次,所以時(shí)間復(fù)雜度與節(jié)點(diǎn)數(shù)量成線性關(guān)系。

????????

(三面,開(kāi)放式問(wèn)題,40分鐘)

十三、如何理解前后端分離

????????前后端分離是一種Web應(yīng)用開(kāi)發(fā)模式,它將用戶界面(UI)及前端業(yè)務(wù)邏輯與后端服務(wù)及數(shù)據(jù)處理邏輯分開(kāi),使得前端和后端可獨(dú)立開(kāi)發(fā)與部署。這種模式帶來(lái)了一系列的優(yōu)勢(shì),同時(shí)也對(duì)開(kāi)發(fā)流程和架構(gòu)提出了新的要求。

????????以下是前后端分離的幾個(gè)主要方面和好處:

?1. 角色和技術(shù)棧分離

  • 前端(Front-end):負(fù)責(zé)展示用戶界面和用戶交互,通常使用HTML、CSS和JavaScript等技術(shù)構(gòu)建,使用現(xiàn)代框架和庫(kù)如React、Vue、Angular,進(jìn)行豐富的交互式體驗(yàn)的開(kāi)發(fā)。
  • 后端(Back-end):負(fù)責(zé)處理業(yè)務(wù)邏輯、數(shù)據(jù)庫(kù)交云、認(rèn)證授權(quán)等服務(wù)器端功能,可以使用各種編程語(yǔ)言和框架,如Java Spring Boot、Python Django、Node.js Express等。

?2. 開(kāi)發(fā)和部署獨(dú)立

  • 開(kāi)發(fā)人員可以專注于各自擅長(zhǎng)的領(lǐng)域,前端開(kāi)發(fā)者專注于用戶體驗(yàn)和界面構(gòu)建,后端開(kāi)發(fā)者專注于數(shù)據(jù)處理和業(yè)務(wù)規(guī)則實(shí)現(xiàn)。
  • 前后端代碼可以分別部署在不同的服務(wù)器上,提供更靈活的擴(kuò)展和管理選項(xiàng)。

?3. 通訊通過(guò)API

  • 前后端之間通過(guò)定義良好的API接口交互,通常是RESTful API或GraphQL等形式。
  • 使用JSON或XML等數(shù)據(jù)交換格式,前端通過(guò)HTTP請(qǐng)求與后端通訊。

?4. 增強(qiáng)用戶體驗(yàn)

  • 由于前端可獨(dú)立更新,所以能夠快速響應(yīng)市場(chǎng)變化,提高用戶體驗(yàn)。
  • 前端可實(shí)現(xiàn)單頁(yè)面應(yīng)用(SPA),動(dòng)態(tài)加載內(nèi)容而無(wú)需重新加載整個(gè)頁(yè)面。

?5. 提高開(kāi)發(fā)效率

  • 前后端分離允許前后端團(tuán)隊(duì)并行工作,只要API契約定義好,雙方即可獨(dú)立進(jìn)行開(kāi)發(fā)。
  • 可利用各種前端開(kāi)發(fā)和調(diào)試工具,加快前端開(kāi)發(fā)進(jìn)度。

?6. 便于擴(kuò)展和維護(hù)

  • 各自的更新和維護(hù)不會(huì)互相影響,減少了開(kāi)發(fā)和部署的復(fù)雜性。
  • 由于前后端的解耦,更容易對(duì)系統(tǒng)進(jìn)行擴(kuò)展和整合新技術(shù)。

????????盡管前后端分離帶來(lái)了上述優(yōu)點(diǎn),但同時(shí)也帶來(lái)了一些挑戰(zhàn),例如跨域資源共享(CORS)問(wèn)題、API版本管理、前后端接口聯(lián)調(diào)需要更好的溝通和文檔支持等。解決這些挑戰(zhàn)需要團(tuán)隊(duì)之間良好的溝通,以及合適的工具和流程來(lái)協(xié)調(diào)工作。

????????

十四、有哪些后端開(kāi)發(fā)經(jīng)驗(yàn),做了什么

????????應(yīng)該準(zhǔn)備一個(gè)簡(jiǎn)潔而詳細(xì)的回答來(lái)展示你的后端開(kāi)發(fā)技能、所使用的技術(shù)棧以及你在以往項(xiàng)目中的具體貢獻(xiàn)。以下是幾個(gè)方面參考:

?1. 概述后端技術(shù)棧
????????開(kāi)始時(shí)簡(jiǎn)要介紹你使用過(guò)的后端語(yǔ)言和框架,如Java/Spring Boot、C#/ASP.NET、Python/Django、Node.js/Express等。

?2. 描述特定的項(xiàng)目經(jīng)驗(yàn)
????????提供一個(gè)或幾個(gè)具體的項(xiàng)目例子,這些例子應(yīng)該能夠反映出你在后端開(kāi)發(fā)方面的專業(yè)水平和經(jīng)驗(yàn)。對(duì)每個(gè)項(xiàng)目,介紹以下信息:

  • 項(xiàng)目的目標(biāo)和你的角色。
  • 使用的技術(shù)棧和工具。
  • 你主要負(fù)責(zé)的功能和任務(wù)。
  • 所解決的關(guān)鍵問(wèn)題和挑戰(zhàn)。
  • 項(xiàng)目的成果和你對(duì)成功所做的貢獻(xiàn)。

?3. 展示解決問(wèn)題的能力
????????談?wù)勀阍诤蠖碎_(kāi)發(fā)中遇到的最有挑戰(zhàn)性的問(wèn)題以及你是如何解決這些問(wèn)題的。

?4. 強(qiáng)調(diào)團(tuán)隊(duì)合作
????????如果適用,討論你如何與前端開(kāi)發(fā)者、設(shè)計(jì)師和其他團(tuán)隊(duì)成員合作,以確保項(xiàng)目的順利進(jìn)行。

?5. 討論性能和安全
????????如果你有在項(xiàng)目中針對(duì)性能優(yōu)化或安全措施做出貢獻(xiàn)的經(jīng)驗(yàn),一定要提到。

?6. 提供維護(hù)和擴(kuò)展的經(jīng)驗(yàn)
????????如果你參與了現(xiàn)有項(xiàng)目的維護(hù)或是為系統(tǒng)提供了擴(kuò)展功能,說(shuō)明你的工作如何提高了代碼質(zhì)量、系統(tǒng)可靠性或用戶體驗(yàn)。

?7. 量化成果
????????如果可能,提供一些量化的結(jié)果,比如性能提升的百分比、處理的請(qǐng)求量、減少的加載時(shí)間等。
????????

?示例:

????????“我在后端開(kāi)發(fā)方面有5年的經(jīng)驗(yàn),主要使用Java和Spring Boot框架。我參與過(guò)多個(gè)企業(yè)級(jí)項(xiàng)目,例如開(kāi)發(fā)了一個(gè)支持?jǐn)?shù)百萬(wàn)并發(fā)用戶的電子商務(wù)平臺(tái),其中我負(fù)責(zé)實(shí)現(xiàn)訂單處理系統(tǒng)和用戶身份驗(yàn)證模塊。

????????除了Java,我也使用過(guò)Node.js開(kāi)發(fā)API服務(wù),并且熟悉數(shù)據(jù)庫(kù)技術(shù),比如MySQL和MongoDB。在最近的一個(gè)項(xiàng)目中,我優(yōu)化了數(shù)據(jù)庫(kù)查詢,使關(guān)鍵操作的速度提高了30%以上。

????????我還處理過(guò)對(duì)系統(tǒng)安全的改進(jìn)。我曾經(jīng)實(shí)現(xiàn)了一套基于OAuth 2.0的權(quán)限管理系統(tǒng),確保了我們的用戶數(shù)據(jù)的安全性。團(tuán)隊(duì)合作方面,我通常與前端開(kāi)發(fā)人員密切協(xié)作,確定API規(guī)格,并通過(guò)持續(xù)集成和代碼評(píng)審來(lái)維護(hù)代碼質(zhì)量。我們的協(xié)作導(dǎo)致了項(xiàng)目按時(shí)交付,客戶反饋表明用戶滿意度顯著提高?!?/p>

????????根據(jù)自己的經(jīng)驗(yàn)調(diào)整這個(gè)回答,保持真實(shí)性,并根據(jù)應(yīng)聘的崗位特點(diǎn)強(qiáng)調(diào)最相關(guān)的部分。

????????

十五、介紹HashMap與TreeMap區(qū)別

? ? HashMap?和?TreeMap?是 Java 的兩種常用的?Map?實(shí)現(xiàn),它們都提供了鍵-值對(duì)存儲(chǔ)機(jī)制,但在內(nèi)部工作原理和特性上有所不同。以下是它們之間的主要區(qū)別:

?1. 內(nèi)部結(jié)構(gòu)

  • HashMap?基于散列表(哈希表)實(shí)現(xiàn),使用哈希函數(shù)來(lái)確定每個(gè)鍵值對(duì)(節(jié)點(diǎn))的存儲(chǔ)位置。
  • TreeMap?基于紅黑樹(shù)實(shí)現(xiàn),紅黑樹(shù)是一種自平衡的排序二叉樹(shù)。

?2. 排序

  • HashMap?不保證任何排序,鍵值對(duì)的存儲(chǔ)是根據(jù)哈希值來(lái)決定的,迭代它時(shí)得到的順序是無(wú)序的。
  • TreeMap?根據(jù)鍵的自然順序或者構(gòu)造時(shí)所指定的?Comparator?進(jìn)行排序。這意味著鍵會(huì)按升序排列,或者按?Comparator?實(shí)現(xiàn)的順序排列。

?3. 時(shí)間復(fù)雜度

  • HashMap?提供了常數(shù)時(shí)間的性能,即?O(1),對(duì)于?get、put?和?remove?操作,理想情況下是這樣。但是,在最壞的情況下(例如當(dāng)所有元素都映射到同一個(gè)桶中時(shí)),性能可能會(huì)退化到?O(n)。
  • TreeMap?保證了?getput?和?remove?操作的時(shí)間復(fù)雜度為?O(log n),因?yàn)樗腔跇?shù)的。

?4. null 值

  • HashMap?允許鍵和值為?null,意味著你可以將?null?作為一個(gè)鍵或值插入到?HashMap?中。
  • TreeMap?不允許鍵為?null(因?yàn)樗枰凑漳撤N順序?qū)︽I進(jìn)行排序),但允許值為?null。

?5. 線程安全

  • 兩者都不是線程安全的。在多線程環(huán)境下,如果沒(méi)有正確的同步,任何結(jié)構(gòu)性修改都可能引發(fā)并發(fā)問(wèn)題。
  • 如果需要線程安全,可以通過(guò)?Collections.synchronizedMap?來(lái)包裝?HashMap,或者使用?ConcurrentHashMap?代替?HashMap。而?TreeMap?沒(méi)有直接的線程安全對(duì)應(yīng),但可以考慮使用?ConcurrentSkipListMap。

?6. 性能

  • HashMap?通常在大部分場(chǎng)景下提供更好的性能,尤其是在添加和查詢?cè)貢r(shí)。而?TreeMap?在維持映射的有序狀態(tài)方面表現(xiàn)更好,尤其適用于需要有序遍歷鍵時(shí)。

????????選擇?HashMap?還是?TreeMap?取決于應(yīng)用程序的具體需求。如果不需要排序,并且想要最快的訪問(wèn)速度,HashMap?是較好的選項(xiàng)。如果需要一個(gè)總是處于排序狀態(tài)的鍵集合,TreeMap?是更加適合的選擇。

????????

十六、?HashMap實(shí)現(xiàn)?個(gè)有過(guò)期功能的緩存

要使用 HashMap 實(shí)現(xiàn)一個(gè)具有過(guò)期功能的緩存,可以創(chuàng)建一個(gè)包裝類,這個(gè)類將包含每個(gè)緩存項(xiàng)的值和過(guò)期時(shí)間。我們可以在每次訪問(wèn)緩存時(shí)檢查該項(xiàng)是否過(guò)期。如果過(guò)期,我們就從緩存中移除這個(gè)項(xiàng)。另外,我們還可以創(chuàng)建一個(gè)維護(hù)過(guò)期項(xiàng)的線程或定時(shí)任務(wù),來(lái)定期清理過(guò)期的緩存項(xiàng)。

下面是一個(gè)簡(jiǎn)單的緩存實(shí)現(xiàn),使用了 HashMap:

import java.util.concurrent.*;

public class ExpiringCache<K, V> {
    // 緩存項(xiàng)類包含值和過(guò)期時(shí)間
    private class CacheItem {
        V value;
        long expiryTime;

        public CacheItem(V value, long expiryTime) {
            this.value = value;
            this.expiryTime = expiryTime;
        }
    }

    private final ConcurrentHashMap<K, CacheItem> cacheMap;
    private final ScheduledExecutorService executorService;

    public ExpiringCache() {
        cacheMap = new ConcurrentHashMap<>();
        executorService = Executors.newSingleThreadScheduledExecutor();

        // 定期執(zhí)行過(guò)期緩存清理任務(wù)
        executorService.scheduleAtFixedRate(() -> {
            long currentTime = System.currentTimeMillis();
            cacheMap.entrySet().removeIf(entry -> currentTime > entry.getValue().expiryTime);
        }, 1, 1, TimeUnit.SECONDS);
    }

    // 向緩存添加項(xiàng),并設(shè)置過(guò)期時(shí)間
    public void put(K key, V value, long expiryDurationInMillis) {
        long expiryTime = System.currentTimeMillis() + expiryDurationInMillis;
        cacheMap.put(key, new CacheItem(value, expiryTime));
    }

    // 從緩存中獲取項(xiàng),如果不存在或已過(guò)期,則返回 null
    public V get(K key) {
        CacheItem item = cacheMap.get(key);
        if (item != null && System.currentTimeMillis() < item.expiryTime) {
            return item.value;
        }

        cacheMap.remove(key); // 如果已過(guò)期,移除
        return null;
    }

    public void shutdown() {
        executorService.shutdownNow();
    }
}

????????在以上代碼中,我們創(chuàng)建了一個(gè)內(nèi)部類?CacheItem?來(lái)存儲(chǔ)緩存的值和該項(xiàng)的過(guò)期時(shí)間。通過(guò)?ScheduledExecutorService, 我們安排了定期執(zhí)行的任務(wù),以清理所有過(guò)期的緩存項(xiàng)。put?方法添加緩存項(xiàng)時(shí)需要指定一個(gè)過(guò)期時(shí)間。get?方法只返回未過(guò)期的緩存項(xiàng),如果檢測(cè)到緩存項(xiàng)已過(guò)期,則將其移除。

????????這個(gè)實(shí)現(xiàn)是線程安全的,因?yàn)槲覀兪褂昧?ConcurrentHashMap,它是一個(gè)支持完全并發(fā)的哈希表。我們也使用了?ScheduledExecutorService?來(lái)定期檢查和清除過(guò)期項(xiàng)。

????????請(qǐng)記得,在停止使用緩存或者程序結(jié)束時(shí)調(diào)用?shutdown()?方法來(lái)關(guān)閉?ScheduledExecutorService。這很重要,因?yàn)槲覀儾幌M笈_(tái)線程在不需要時(shí)繼續(xù)運(yùn)行。

????????

????????Google 的 Guava 庫(kù)中包含了一個(gè)功能強(qiáng)大的緩存實(shí)現(xiàn)?Cache?類(你可以自己用Cache來(lái)實(shí)現(xiàn)緩存過(guò)期功能試試)。

????????下面是使用 Guava 緩存的一個(gè)簡(jiǎn)單例子:

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;

import java.util.concurrent.TimeUnit;

public class GuavaCacheExample {

    public static void main(String[] args) throws Exception {
        // 創(chuàng)建緩存
        LoadingCache<String, String> cache = CacheBuilder.newBuilder()
                .maximumSize(100)                       // 最多緩存項(xiàng)
                .expireAfterWrite(10, TimeUnit.MINUTES) // 寫(xiě)入10分鐘后過(guò)期
                .build(
                        new CacheLoader<String, String>() {
                            public String load(String key) {
                                return fetchData(key);
                            }
                        });

        // 從緩存中取值,可能直接取緩存,或者加載數(shù)據(jù)后緩存
        String value = cache.get("myKey");
        System.out.println("Value for 'myKey': " + value);
        
        // 直接向緩存里添加一個(gè)鍵值對(duì)
        cache.put("anotherKey", "anotherValue");

        // 得到某個(gè)鍵對(duì)應(yīng)的值(如果存在)
        System.out.println("Value for 'anotherKey': " + cache.getIfPresent("anotherKey"));
    }

    // 示范的數(shù)據(jù)加載方法,實(shí)際應(yīng)用中應(yīng)更復(fù)雜,例如數(shù)據(jù)庫(kù)查詢操作
    private static String fetchData(String key) {
        // Here you should implement actual data fetching logic
        return "Data for " + key;
    }
}

????????在這個(gè)例子中,我們使用 Guava 來(lái)創(chuàng)建一個(gè)緩存,它有一個(gè)最大項(xiàng)數(shù)限制,并且每個(gè)緩存項(xiàng)在寫(xiě)入10分鐘后會(huì)自動(dòng)過(guò)期。CacheLoader?被用來(lái)定義如何加載數(shù)據(jù)到緩存中。當(dāng)你調(diào)用?get()?方法時(shí),Guava 自動(dòng)使用定義好的加載機(jī)制來(lái)提供值。如果緩存中已經(jīng)有這個(gè)值了,就會(huì)立刻返回。

????????Guava 的?Cache?類也提供了很多其他功能,比如監(jiān)聽(tīng)器,手動(dòng)移除,緩存統(tǒng)計(jì)等。

????????如果需要在商業(yè)項(xiàng)目中使用緩存,推薦使用成熟的緩存框架,比如 Guava,Caffeine,Ehcache 或者 Hazelcast 等。這些框架提供了更復(fù)雜的緩存策略,性能監(jiān)控,以及和其他技術(shù)的集成。

? ? ? ??

十七、平時(shí)怎么學(xué)習(xí)新知識(shí)

? ? ? ? 下面是一些常見(jiàn)的學(xué)習(xí)方法和技巧:

  1. 設(shè)定學(xué)習(xí)目標(biāo):開(kāi)始學(xué)習(xí)前,先設(shè)定清晰的、具體的學(xué)習(xí)目標(biāo),這可以幫助你保持專注并衡量自己的進(jìn)步。

  2. 按計(jì)劃學(xué)習(xí):建立一個(gè)學(xué)習(xí)計(jì)劃,為每個(gè)學(xué)習(xí)階段設(shè)定時(shí)間表和里程碑,按計(jì)劃執(zhí)行可以提高學(xué)習(xí)效率。

  3. 多樣化學(xué)習(xí)渠道:使用書(shū)籍、在線課程、視頻教學(xué)、博客文章、技術(shù)文檔等不同的學(xué)習(xí)資源可以幫助你全面理解新知識(shí)。

  4. 實(shí)踐操作:通過(guò)實(shí)際編程、設(shè)計(jì)、寫(xiě)作或其他實(shí)踐活動(dòng)將所學(xué)知識(shí)運(yùn)用到實(shí)際中去,實(shí)踐是檢驗(yàn)學(xué)習(xí)成果的最佳方式。

  5. 參與討論:加入學(xué)習(xí)小組或在線社區(qū),參與討論可以讓你從不同的角度理解新知識(shí),同時(shí),解答他人問(wèn)題也是一種很好的學(xué)習(xí)方式。

  6. 建立聯(lián)系:嘗試將新學(xué)的知識(shí)和你已經(jīng)知道的知識(shí)聯(lián)系起來(lái),這樣有助于記憶和深化理解。

  7. 定期復(fù)習(xí):周期性地檢查和復(fù)習(xí)你所學(xué)的內(nèi)容,避免遺忘,并確保知識(shí)點(diǎn)能夠牢固記在腦中。

  8. 靈活調(diào)整:在學(xué)習(xí)過(guò)程中,根據(jù)自己的學(xué)習(xí)進(jìn)展和理解情況,適當(dāng)調(diào)整學(xué)習(xí)目標(biāo)和計(jì)劃。

  9. 保持好奇心和耐心:學(xué)習(xí)新知識(shí)可能會(huì)遇到困難和挑戰(zhàn),保持開(kāi)放和有好奇心的態(tài)度是很重要的,耐心地對(duì)待每一步學(xué)習(xí)過(guò)程。

  10. 運(yùn)用現(xiàn)代技術(shù)輔助學(xué)習(xí):可以利用各種軟件和Apps來(lái)輔助學(xué)習(xí),比如使用筆記軟件整理學(xué)習(xí)筆記,用時(shí)間管理工具追蹤學(xué)習(xí)時(shí)間等。

????????

十八、最近看了什么書(shū)

? ? ? ? 這個(gè)就?由發(fā)揮了。

????????要回答好這個(gè)問(wèn)題,一定要保持看書(shū)學(xué)習(xí)的狀態(tài),否則肯定回答不好這個(gè)問(wèn)題,至少不能瞎編,多問(wèn)兩個(gè)問(wèn)題就被看穿。

? ? ? ? 所以,隨時(shí)保持學(xué)習(xí)充電狀態(tài)。一起加油!未來(lái)可期。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-802337.html

到了這里,關(guān)于Java入門高頻考查基礎(chǔ)知識(shí)4(字節(jié)跳動(dòng)面試題18題2.5萬(wàn)字參考答案)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Java入門基礎(chǔ)知識(shí)

    Java入門基礎(chǔ)知識(shí)

    JDK是Java工具開(kāi)發(fā)包,包含了JVM(程序運(yùn)行環(huán)境),核心類庫(kù)(直接應(yīng)用即可),開(kāi)發(fā)工具(Javac,java,jdb,jhat…) JRE是Java運(yùn)行環(huán)境,包含了JVM,核心類庫(kù),運(yùn)行工具 JDK包含了JRE,JRE包含了jvm 全部小寫(xiě)(有特定含義的英文字符) class 表示一個(gè)類 整數(shù)類型 小數(shù)類型 字符串類型 :只用\\\"雙引

    2024年02月09日
    瀏覽(92)
  • Java基礎(chǔ)入門知識(shí)

    以下是學(xué)習(xí)java必備的知識(shí) 目錄 前言 一、Java入門 二、基本數(shù)據(jù)類型與數(shù)組 標(biāo)識(shí)符與 2. 基本數(shù)據(jù)類型 3. 類型轉(zhuǎn)換運(yùn)算 4. 運(yùn)算符 5. 數(shù)組 6.控制結(jié)構(gòu)(與c使用一致) 總結(jié) Java語(yǔ)言是面向?qū)ο缶幊陶Z(yǔ)言,編寫(xiě)的軟件與平臺(tái)無(wú)關(guān)。具有語(yǔ)法簡(jiǎn)單、面向?qū)ο蟆⒎€(wěn)定、與平臺(tái)無(wú)

    2024年02月16日
    瀏覽(92)
  • Linux 網(wǎng)絡(luò)基礎(chǔ)(1)基礎(chǔ)知識(shí)、IP地址、端口、協(xié)議、網(wǎng)絡(luò)字節(jié)序

    Linux 網(wǎng)絡(luò)基礎(chǔ)(1)基礎(chǔ)知識(shí)、IP地址、端口、協(xié)議、網(wǎng)絡(luò)字節(jié)序

    網(wǎng)絡(luò)發(fā)展背景: 網(wǎng)絡(luò)的劃分:局域網(wǎng)(覆蓋范圍在1000m以內(nèi))、城域網(wǎng)(覆蓋范圍在20km以內(nèi))、廣域網(wǎng)(更大范圍) 組網(wǎng)方式:以太網(wǎng)、令牌環(huán)網(wǎng).... 日常名詞:互聯(lián)網(wǎng),因特網(wǎng)----說(shuō)的是一個(gè)網(wǎng)絡(luò),就是國(guó)際化的廣域網(wǎng) 網(wǎng)卡:實(shí)現(xiàn)數(shù)字信號(hào)與電信號(hào)之間的轉(zhuǎn)換 中繼器:信號(hào)

    2024年02月05日
    瀏覽(37)
  • p7付費(fèi)課程筆記:jvm基礎(chǔ)知識(shí)、字節(jié)碼、類加載器

    p7付費(fèi)課程筆記:jvm基礎(chǔ)知識(shí)、字節(jié)碼、類加載器

    機(jī)器語(yǔ)言-編程語(yǔ)言-高級(jí)語(yǔ)言(java,c++,Go,Rust等) 面向過(guò)程–面向?qū)ο?面向函數(shù) java是一種面向?qū)ο?、靜態(tài)類型、編譯執(zhí)行,有VM(虛擬機(jī))/GC和運(yùn)行時(shí)、跨平臺(tái)的高級(jí)語(yǔ)言。重點(diǎn):VM(虛擬機(jī))/GC(Garbage Collector)和運(yùn)行時(shí)、跨平臺(tái)。 跨平臺(tái)步驟:字節(jié)碼文件被虛擬機(jī)加載(

    2024年02月10日
    瀏覽(18)
  • 云計(jì)算第1階段_Linxu基礎(chǔ)知識(shí)_day03,字節(jié)跳動(dòng)8年老Linux運(yùn)維面試官經(jīng)驗(yàn)談

    云計(jì)算第1階段_Linxu基礎(chǔ)知識(shí)_day03,字節(jié)跳動(dòng)8年老Linux運(yùn)維面試官經(jīng)驗(yàn)談

    5 遠(yuǎn)程連接sshd服務(wù) ps:sshd默認(rèn)端口號(hào):22 5.1 手動(dòng)修改默認(rèn)端口號(hào) 6 文件拷貝、移動(dòng)、刪除 6.1 拷貝文件或目錄 6.2 移動(dòng)文件或目錄 **ps:**判斷上一條命令是否執(zhí)行成功 命令:echo $? 如果返回值為0,證明我們上一條命令執(zhí)行是成功的, 如果返回值非0,證明我們上一條命令執(zhí)行

    2024年04月12日
    瀏覽(52)
  • stm32串口自定義協(xié)議接收一串十六進(jìn)制數(shù)據(jù)(將其中兩個(gè)字節(jié)轉(zhuǎn)化為十進(jìn)制數(shù)據(jù))+部分串口基礎(chǔ)知識(shí)

    stm32串口自定義協(xié)議接收一串十六進(jìn)制數(shù)據(jù)(將其中兩個(gè)字節(jié)轉(zhuǎn)化為十進(jìn)制數(shù)據(jù))+部分串口基礎(chǔ)知識(shí)

    位(bit): 二進(jìn)制數(shù)中的一個(gè)數(shù)位,可以是0或者1,是計(jì)算機(jī)中數(shù)據(jù)的最小單位。 字節(jié)(Byte): 計(jì)算機(jī)中數(shù)據(jù)的基本單位,每8位組成一個(gè)字節(jié)。各種信息在計(jì)算機(jī)中存儲(chǔ)、處理至少需要一個(gè)字節(jié)。 例如,一個(gè)ASCII碼用一個(gè)字節(jié)表示,一個(gè)漢字用兩個(gè)字節(jié)表示。 字(Word):

    2023年04月08日
    瀏覽(27)
  • Opengl入門基礎(chǔ)-基礎(chǔ)知識(shí)

    通過(guò)之前的教程,我們已經(jīng)擁有了開(kāi)發(fā)環(huán)境,但是在真正開(kāi)發(fā)程序之前,我們首先了解下Opengl的基本概念。 Opengl是什么? 通常網(wǎng)上會(huì)說(shuō)Opengl是一種規(guī)范,一種接口,但是這種說(shuō)法有點(diǎn)抽象,我們不妨先看看下面這個(gè)簡(jiǎn)單的gl流程 代碼中可能有人對(duì)GLFW_OPENGL_PROFILE這類參數(shù)感到

    2024年02月11日
    瀏覽(20)
  • 計(jì)算機(jī)基礎(chǔ)知識(shí)(基礎(chǔ)入門小白專屬)

    ?? 作者:小劉在這里 ?? 每天分享云計(jì)算網(wǎng)絡(luò)運(yùn)維課堂筆記,疫情之下,你我素未謀面,但你一定要平平安安,一? 起努力,共赴美好人生! ?? 夕陽(yáng)下,是最美的,綻放,愿所有的美好,再疫情結(jié)束后如約而至。 目錄 計(jì)算機(jī)的發(fā)展史 計(jì)算機(jī)的硬件組成 計(jì)算機(jī)的分類

    2024年02月08日
    瀏覽(21)
  • QT入門基礎(chǔ)知識(shí)

    QT入門基礎(chǔ)知識(shí)

    什么是QT QT是一個(gè)跨平臺(tái)的C++圖像用戶界面應(yīng)用程序框架 QT在1991年由奇趣科技開(kāi)發(fā) QT的優(yōu)點(diǎn) 跨平臺(tái),幾乎支持所有平臺(tái) 接口簡(jiǎn)單,容易上手 一定程度上簡(jiǎn)化了內(nèi)存回收機(jī)制 有很好的社區(qū)氛圍 可以進(jìn)行嵌入式開(kāi)發(fā) QT注意事項(xiàng) 命名規(guī)范 類名 首字母大寫(xiě),單詞和單詞之間首字母

    2024年02月10日
    瀏覽(133)
  • 電腦入門基礎(chǔ)知識(shí)

    答:一般情況下,電腦鍵盤只有一個(gè)。但是,也有一些特殊的情況,例如游戲玩家可能會(huì)使用額外的游戲鍵盤,或者一些專業(yè)人士可能會(huì)使用多個(gè)鍵盤來(lái)提高工作效率。但是在大多數(shù)情況下,一臺(tái)電腦通常只會(huì)連接一個(gè)鍵盤。 答:外接鍵盤和筆記本鍵盤的按鍵數(shù)可能會(huì)有所不

    2024年02月04日
    瀏覽(23)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包