面試經(jīng)歷 | 快手Java開(kāi)發(fā) 2021.09

面試崗位

Java開(kāi)發(fā)工程師(校招)

一面(2021.0914)

快手不知道為啥沒(méi)有統(tǒng)一筆試,直接發(fā)起的面試。問(wèn)的八股文很全面,算法題出的也讓我感覺(jué)很好。

基礎(chǔ)題

  1. Java基礎(chǔ)數(shù)據(jù)類(lèi)型有哪些,占多少位?
    答:共有8種,分別是:

    1. boolean 布爾:1位
    2. byte 字節(jié):8位
    3. short 短整數(shù):16位,2字節(jié)
    4. char 字符:16位,2字節(jié)
    5. int 整型:32位,4字節(jié)
    6. float 單精度:32位,4字節(jié)
    7. long 長(zhǎng)整數(shù):64位,8字節(jié)
    8. double 雙精度:64位,8字節(jié)
  2. double運(yùn)算時(shí)需要注意什么?為什么
    答:精度丟失,比方說(shuō)當(dāng)比較時(shí),可以用差的絕對(duì)值小于一個(gè)極小值 \epsilon 來(lái)說(shuō)明兩個(gè)變量相等。原因是做計(jì)算時(shí)十進(jìn)制會(huì)先轉(zhuǎn)換成二進(jìn)制,但是有的十進(jìn)制轉(zhuǎn)換成二進(jìn)制是無(wú)限小數(shù),必然會(huì)有精度舍棄。

  3. 你知道 float 是怎么存儲(chǔ)小數(shù)的嗎?
    答:以 6.5432 為例,整數(shù)部分用模二取余法:
    6 / 2 = 3 …… 0
    3 / 2 = 1 …… 1
    1 / 2 = 0 …… 1
    得到 6 的二進(jìn)制表示 110。小數(shù)部分用乘二取整法:
    0.5432 * 2 = 1 + 0.0864
    0.0864 * 2 = 0 + 0.1728
    0.1728 * 2 = 0 + 0.3456
    0.3456 * 2 = 0 + 0.6912
    0.6912 * 2 = 1 + 0.3824
    0.3824 * 2 = 0 + 0.7648
    0.7648 * 2 = 1 + 0.5296
    可以得到 0.5432_{(10)} ≈ 0.1000101_{(2)}
    組合得到二進(jìn)制為 110.1000101_{(2)}
    左移兩位,使小數(shù)點(diǎn)前只有一位 1,即1.101000101_{(2)} * 2^2,則存儲(chǔ)時(shí)指數(shù)為 2+127=129
    則最終 6.5432 存儲(chǔ)結(jié)果為 0(符號(hào)位) 10000001(指數(shù)) 1010001 01000000 00000000

  4. volatile關(guān)鍵字作用
    參考資料《【Java線程】volatile的適用場(chǎng)景》
    答:volatile具有可見(jiàn)性和有序性,但是沒(méi)有原子性。他可以使得它修飾的變量,每次修改時(shí)先同步到主存,每次使用前都從主存直接獲取。這個(gè)操作保證了它的可見(jiàn)性。同時(shí)他的引入將避免指令重排的現(xiàn)象,保證了有序性。
    適用場(chǎng)景:

    • 用來(lái)標(biāo)記某一個(gè)一次性狀態(tài)已發(fā)生
    • 單例模式取消指令重排
    • 獨(dú)立觀察
    • volatile bean
    • 開(kāi)銷(xiāo)較低的讀-寫(xiě)鎖策略
  5. 泛型了解嗎,他有什么用處?
    答:在集合類(lèi)實(shí)現(xiàn)的時(shí)候,如果想實(shí)現(xiàn)一個(gè)通用的可以處理不同類(lèi)型的類(lèi),需要使用Object作為屬性和方法參數(shù)。然后具體操作時(shí)再去做強(qiáng)制轉(zhuǎn)換,一來(lái)是使用時(shí)不方便,二來(lái)是只有運(yùn)行時(shí)才能知道傳入集合的值類(lèi)型是否正確。因此在JDK 1.5之后,引入了泛型的概念。
    泛型的本質(zhì)是參數(shù)化類(lèi)型,把要操作的數(shù)據(jù)類(lèi)型當(dāng)做一個(gè)參數(shù)傳入,這樣在編譯時(shí)就可以對(duì)存放的內(nèi)容的類(lèi)型做安全判斷。

  6. private關(guān)鍵字作用
    答:加了之后的變量和方法,只有在類(lèi)內(nèi)部才能使用,外部不能直接調(diào)用,子類(lèi)也不會(huì)繼承。想調(diào)用的話可以配套寫(xiě)一對(duì)get,set。

  7. 反射了解嗎?他是在編譯階段還是運(yùn)行階段。
    答:運(yùn)行階段,反射就是在運(yùn)行時(shí)才知道要操作的類(lèi)是什么,并且可以在運(yùn)行時(shí)獲取類(lèi)的完整構(gòu)造,并調(diào)用對(duì)應(yīng)的方法。
    比如正常的調(diào)用應(yīng)該是先 new 一個(gè)對(duì)象,然后使用對(duì)象的一些屬性和方法做一些操作。但是反射中可能是先獲得類(lèi),然后通過(guò) getConstructor 方法和 newInstance 方法來(lái)創(chuàng)建一個(gè)對(duì)象以供使用。

  8. 反射可以獲得 private 屬性嗎?他們倆是不是沖突的。
    答:確實(shí)可以用 getDeclaredField 獲得包含私有變量在內(nèi)的所有成員變量。
    private 最主要的目的實(shí)際上是為了實(shí)現(xiàn)封裝性,為類(lèi)內(nèi)的 public 方法提供一些支持,同時(shí)不希望被外部直接調(diào)用,或是繼承。
    反射如果單獨(dú)的使用某個(gè) private 方法或?qū)傩?,大概率是沒(méi)有什么作用的,因?yàn)楸旧?private 變量可能就已經(jīng)配套有 getset;而單獨(dú)調(diào)用 private 方法可能導(dǎo)致程序異常;同時(shí)原本繼承該類(lèi)的子類(lèi)依然不能繼承得到 private 成員變量。因此我們可以認(rèn)為反射對(duì)我們希望實(shí)現(xiàn)的封裝性(及一個(gè)父類(lèi)的一些內(nèi)部使用方法不影響外部環(huán)境),基本沒(méi)有影響。

  9. 線程池了解嗎?
    答:由于每次創(chuàng)建、銷(xiāo)毀、或是管理線程都有一定的資源消耗,因此使用線程池,對(duì)線程做統(tǒng)一管理,當(dāng)程序需要線程時(shí),只需要向線程池申請(qǐng),如果某個(gè)線程異常掛掉,那線程池還可以及時(shí)補(bǔ)充。

  10. ThreadPoolExecutor 知道哪些?
    答:SingleThreadExecutor :返回一個(gè)只有一個(gè)線程的線程池,多余的任務(wù)會(huì)被放到消息隊(duì)列里慢慢執(zhí)行。
    FixedThreadPoolExecutor :返回一個(gè)固定線程數(shù)的線程池,任務(wù)來(lái)時(shí),如果有空閑線程就立刻執(zhí)行,否則同樣存放在消息隊(duì)列中;如果線程掛掉,及時(shí)重新創(chuàng)建線程。
    CachedThreadPoolExecutor:可以動(dòng)態(tài)調(diào)整線程池線程數(shù),只要 JVM 能支持,可以無(wú)限開(kāi)線程,同時(shí)如果沒(méi)有任務(wù)需要也會(huì)自動(dòng)回收。
    ScheduledThreadPoolExecutor:周期性執(zhí)行任務(wù)

  11. ThreadPoolExecutor 有哪些參數(shù)?
    答:(當(dāng)時(shí)并沒(méi)有答出來(lái))
    corePoolSize:核心線程數(shù),及最小同時(shí)運(yùn)行線程數(shù)量。
    workQueue:當(dāng)新任務(wù)來(lái)時(shí)先判斷線程數(shù)是否到核心線程數(shù),若達(dá)到,則放進(jìn)任務(wù)隊(duì)列中。
    maximumPoolSize:當(dāng)隊(duì)列達(dá)到容量上限時(shí),將同時(shí)運(yùn)行線程數(shù)變?yōu)樽畲缶€程數(shù)。
    keepAliveTime:若當(dāng)前實(shí)際任務(wù)數(shù)不超過(guò)核心線程數(shù),但運(yùn)行中的線程數(shù)超過(guò)了時(shí),等待keepAliveTime 時(shí)間后,才進(jìn)行銷(xiāo)毀。
    unitkeepAliveTime參數(shù)的實(shí)踐單位
    threadFactory:創(chuàng)建新線程的工廠類(lèi)
    handler:飽和策略:線程容量和隊(duì)列容量同時(shí)飽和時(shí)執(zhí)行策略。包括①拒絕新任務(wù) ②增加隊(duì)列容量 ③ 直接丟棄 ④ 丟棄最早任務(wù)。默認(rèn)使用第一種。

  12. GC 了解嗎,怎么判斷某個(gè)對(duì)象應(yīng)該被回收?
    答:兩種方法:引用計(jì)數(shù)法和可達(dá)性分析。
    引用計(jì)數(shù):對(duì)于某個(gè)對(duì)象,每有一個(gè)地方引用他,計(jì)數(shù)器加 1,引用時(shí)效,計(jì)數(shù)器減 1。當(dāng)計(jì)數(shù)值為 0 時(shí)說(shuō)明對(duì)象應(yīng)該被回收。
    可達(dá)性分析:從 GC root 出發(fā),所有不可達(dá)的對(duì)象會(huì)被標(biāo)記。 GC root 有以下幾種: ①虛擬機(jī)棧:棧幀中的本地變量表引用的對(duì)象 ②native方法引用的對(duì)象 ③方法去中的靜態(tài)變量和常量引用的對(duì)象

  13. G1 怎么做的標(biāo)記和清除,過(guò)程是什么?
    答:G1 會(huì)將內(nèi)存劃分成若干個(gè)小塊,且標(biāo)記為老年代、Eden、Survivor,然后執(zhí)行Young GC,如果對(duì)象存活就會(huì)被轉(zhuǎn)移到Survivor 上,如果存活時(shí)間多于閾值,就會(huì)晉升老年代。而 G1 的老年代垃圾回收,就或用到標(biāo)記清理過(guò)程:

    • 初始標(biāo)記:Stop the World,標(biāo)記可能有引用指向老年代對(duì)象的 Survivor 區(qū),此操作與一次 Young GC 同時(shí)。
    • 掃描根區(qū)域:掃描 Survivor 區(qū)中引用到老年代的引用。
    • 并發(fā)標(biāo)記:在堆上找活著的對(duì)象,并標(biāo)記
    • 再次標(biāo)記:Stop the World,完成堆內(nèi)存中存活對(duì)象標(biāo)記,使用 SATB 算法
    • 清理:Stop the World,統(tǒng)計(jì)+擦寫(xiě)+重置空 heap 區(qū)
    • 拷貝:Stop the World,轉(zhuǎn)移或拷貝存活對(duì)象到未使用的 heap 區(qū)
  14. 三次握手四次揮手
    答:握手時(shí):甲說(shuō)嘿我要和你聊天了,乙回復(fù)我知道了,甲回復(fù)乙我知道你知道了。此時(shí)雙方確認(rèn)對(duì)方可以接收消息,因此開(kāi)始建立連接發(fā)送消息。
    揮手時(shí):甲說(shuō)我說(shuō)完了,乙說(shuō)好的我知道了,但此時(shí)乙可能還有消息沒(méi)有發(fā)送完畢。等了一會(huì)之后乙也發(fā)送完畢了,通知甲自己要中斷連接了,甲收到之后回信知道了,并中斷連接,乙收到后也中斷連接。
    在兩個(gè)過(guò)程中,都是通過(guò)比方說(shuō)一個(gè)發(fā)送信號(hào) x,另一個(gè)發(fā)送 x+1 這樣的形式,驗(yàn)證對(duì)方確實(shí)收到自己發(fā)出的信號(hào)。

  15. TCP是什么?
    答:TCP是面向連接的,全雙工的,可以提供可靠地連接服務(wù)。連接時(shí)使用三次握手,斷連時(shí)使用四次揮手。TCP可以通過(guò)確認(rèn)、重傳、窗口、擁塞控制等機(jī)制保證數(shù)據(jù)正確性,但效率較低,且開(kāi)銷(xiāo)比UDP要大。

  16. MYSQL 索引的數(shù)據(jù)結(jié)構(gòu)什么樣?
    答:B+ 樹(shù),B 樹(shù)是在中間節(jié)點(diǎn)及葉子節(jié)點(diǎn)都可以存放信息的一棵樹(shù),而 B+ 樹(shù)則是所有信息均被存放在葉子節(jié)點(diǎn),且在所有葉子節(jié)點(diǎn)間,從左至右存在一條鏈表,這樣的好處是比方說(shuō)我們想查一段區(qū)間中的索引值,那我們只需要找到兩端,然后通過(guò)那條鏈表就可以很快的獲取到我們想要的所有數(shù)據(jù)信息。而且B+樹(shù)查詢(xún)更穩(wěn)定。

算法題

很喜歡這個(gè)算法題,不難但是考察有沒(méi)有刷過(guò)題非常好。

  1. 給一個(gè)鏈表 1,2,3,4,5,...,n,把他變成1,n,2,n-1,...這種形式的鏈表返回
    答:先快慢指針找到中間點(diǎn),然后把右半段鏈表逆序,然后雙指針兩頭向中間靠近。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容