首頁 >Java >Java面試題 >順豐科技面試

順豐科技面試

Java后端技术全栈
Java后端技术全栈轉載
2023-08-15 15:52:171285瀏覽

本來約的三點的面試,但是面試官提前上線看到我在線就說提前開始吧。

先看問題

  1. #自我介紹
  2. 說一個你認為有挑戰的專案
  3. 怎麼學習Java的
  4. 說一下抽象類別和介面
  5. 說HashMap和Hashtable
  6. HashMap加入一個元素的流程
  7. 什麼是紅黑樹,特點是什麼  ?
  8. B 樹的特點,有幾層,最大可以存放多少資料
  9. MySQL的索引為什麼要使用B 樹而不使用跳表?
  10. Redis為什麼要使用跳表而不使用B 樹或二元樹呢?
  11. 建立索引需要注意些什麼?
  12. 如果單表資料量過千萬,怎麼優化?
  13. 一個500w條資料的表a,一個300w資料的表b,透過外鍵tid 關聯,如何最快的查詢出滿足條件的第50000到第50200中的這200筆數據記錄?
  14. 說JVM的記憶體模型
  15. 為什麼需要Survivor區?
  16. ##你有什麼想問我的嗎?

試題解析

##自我介紹菜鳥的回答:

面試官你好,我叫張三,河南人,畢業於XX大學,從XX年畢業後就一直從事java開發,差不多 3年了吧。來貴公司面試,尋求一份java開發工作。

自我介紹要說幾個點:你是誰,你的優點是什麼?這麼多年你做了啥?在學校獲得過什麼獎?對哪些技術有深入研究?是否有高並發系統的設計?是否參與過什麼大型專案?

總之,把你有的家底都亮出來,讓人家知道你哪方面相對比較強。

說一個你認為有挑戰的項目

這個問題其實是因人而異的,對於剛入門的朋友,叫他搭建個專案就覺得很有挑戰性。

而對大牛來說,「挑戰性」已經不在是技術。更多的是何如包裝項目哄好老闆,如何壓榨自己的下屬才是專案有挑戰性的點。

而在面試環節,有「挑戰性」是對於面試官而言的一個標準。如果這個專案業務這個技術點面試官沒接觸過,聽起來很難,那這個就是一個「有挑戰」的專案。

如果面試官對你所說的挑戰項目很熟悉,此時可能對你來說是個機會也是個挑戰,回答出面試官沒遇到的問題,已經如何解決的,那面試官妥妥的佩服你,反之,面試官知道的這個項目的問題,問你你答不上來,那就回面試大打折扣了。

比如說:五、六年前,你的技術堆疊中有dubbo、Spring Boot 那是很吃香的,但現在已經是標配了。

但是有大數據、高並發、架構改造經驗的開發者還是少,因為絕大部分公司都沒辦法發展成為大公司。但。這也是隨著軟體工程怎麼發展都無法改變的事。

所以對於有挑戰的專案具有以下幾個特點:

1、大數據量

2、高並發

3、架構改造

只要你的專案能跟這幾個東西沾一點邊,那你的專案level就高至少一級。

這裡,我給你一個回答的範本:

1、我負責的是這個xxx業務項目,這個業務的是用來xxx的。

2、前期為了快速試錯,快速回應市場,前期使用了簡單的xxxx方案。

3、隨著業務的發展,這個方案在xxx方面出現xxx的技術問題。

4、為了解決這些技術困難,最終用了xxx方案,然後介紹這些方案,同時這些方案是怎麼解決這些技術問題的。

平常都是怎麼學習Java的

就如實的說自己的學習歷程,但要注意,學習要體現自己是主動的,另外,標註自己有個好習慣:記筆記,好幾下不如爛筆頭。

推薦看官網,看書,看影片。

學習過程中,不斷實踐,不斷反思,不斷總結。

說一下抽象類別和介面

  • #抽象類別要被子類別繼承,介面要被子類別實作。
  • 抽象類別可以有建構方法,介面中不能有建構方法。
  • 抽象類別中可以有普通成員變量,介面中沒有普通成員變量,它的變數只能是公共的靜態的常數
  • 一個類別可以實作多個接口,但是只能繼承一個父類,這個父類可以是抽象類別。
  • 抽象類別中可以作方法聲明,也可以做方法實作。介面中可以做方法聲明,也可以定義default方法。
  • 抽象層級(從高到低):介面>抽象類別>實作類別
  • 抽象類別主要是用來抽象類別,介面主要是用來抽象方法功能。
  • 抽象類別的關鍵字是abstract,介面的關鍵字是interface

#說HashMap和Hashtable

我們可以從五個方面來回答:

  1. #線程是否安全:HashMap 是非線程安全的, HashTable 是線程安全的。因為 HashTable 內部的方法基本上都經過 synchronized 修飾。 (如果你要確保線程安全的話就使用 ConcurrentHashMap);

  2. 效率:因為線程安全的問題, HashMap 要比 HashTable 效率高一點。另外, HashTable基本上被淘汰,不要在程式碼中使用它;

  3. 對Null key 和Null value 的支援:HashMap 可以儲存null 的key 和value,但null 作為鍵只能有一個,null 作為值可以有多個;HashTable 不允許有null 鍵和null 值,否則會拋出NullPointerException 。

  4. 初始容量帶下和每次擴充容量大小的不同 :

    ① 若建立時若不指定容量初始值, Hashtable預設的初始大小為 11,之後每次擴充,容量變成原來的 2n 1。 HashMap 預設的初始化大小為 16。之後每次擴充,容量變成原來的 2 倍。

    ② 創建時如果給定了容量初始值,那麼Hashtable 會直接使用你給定的大小,而HashMap 會將其擴充為2 的冪次方大小( HashMap 中的tableSizeFor( )方法保證)。

  5. 底層資料結構:JDK1.8 以後的HashMap 在解決雜湊衝突時有了較大的變化,當鍊錶長度大於閾值(預設為8 )(將鍊錶轉換成紅黑樹前會判斷,如果當前數組的長度度大於64,那麼會選擇先進行數組擴容,而不是轉換為紅黑樹)時,將鍊錶轉換為紅黑樹,以減少搜尋時間。 Hashtable 沒有這樣的機制。

儘管是普通不能再普通的面試題了,可面試中,照樣很大部分人同學回答的不好。回答中提到了2的n次冪,面試官很有可能會繼續追問相關的問題,如果還不清楚的,建議對HashMap進行系統的學習。

我的部落格上之前發過兩篇文章:

#HashMap新增一個元素的流程

HashMap在put中加入元素過程可以分為下面9個步驟:

  • 1.使用put()方法時,直接調putVal()方法
  • 2.在put的時候先判斷數組是否為空,如果為空則進行resize操作
  • 3.以hash索引數組的長度-1與key的hash值進行與運算,得出在數組中的索引,如果索引指定的位置為空,則代表可以插入,直接插入一個新的node
  • #4.判斷當前的key是否存在,如果存在則進行替換,如果替換成功則傳回舊的值
  • 5.如果key不存在,則判斷目前節點是否為樹型,如果是樹型的話,則依照樹的操作去追加新節點內容
  • 6.如果出現hash衝突的節點不是樹型,則表示目前發生的碰撞在鍊錶裡面,則這個時候就進入迴圈處理邏輯
  • 7.進入循環邏輯之後先判斷被碰撞節點的下一個節點是否為空,如果為空就將新節點放入
  • 8.放入後判斷當前鍊錶是否超過最大允許鍊錶長度8,如果超過則轉為紅黑樹進行插入
  • #9.如果map的索引表為空或當前索引表長度還小於64(最大轉紅黑樹的索引數組表長度),那麼進行resize操作就行了;否則,如果被碰撞節點不為空,那麼就順著被碰撞節點這條樹往後新增該節點插入

可以看看我部落格上的部落格文章:三年必備HashMap原始碼:http://www.woaijava.cc/blog/211

什麼是紅黑樹,特點是什麼?

紅黑樹(Red Black Tree)是一種特化的AVL樹(平衡二叉樹),都是在進行插入和刪除操作時透過特定操作保持二叉查找樹的平衡,從而獲得較高的查找性能。

紅黑樹的特徵有5個:

  • 結點是紅色或黑色。

  • 根結點是黑色。

  • 所有葉子都是黑色(葉子是NIL結點)

  • 每個紅色結點的兩個子結點都是黑色。 (從每個葉子到根的所有路徑上不能有兩個連續的紅色結點)

  • #從任一結點到其每個葉子的所有路徑都包含相同數目的黑色結點。

其實這個問題不難,難得是可能有的面試官會問紅黑樹的操作,左旋轉右旋轉...,我面試過幾百人,能說出來寥寥無幾。

B 樹的特點,有幾層,最大可以存放多少條資料

B 樹的特點有兩個:

  • 1.非葉節點]只具有索引作用,也就是說,非葉子節點只能儲存Key,不能儲存value
  • 2.樹的所有葉節點構成一個有序鍊錶,可以依照key排序的次序依序遍歷全部資料。

B 樹一般是1道3層。

InnoDB頁的大小預設為16KB

  • #假設一筆記錄大小為1KB,則在一個資料頁中可以存16個資料(忽略頁中的其他資料結構)
  • 假設主鍵為int,又指標大小為6B,則在一個索引頁中可以儲存16KB/(4B 6B)≈1638個索引

所以,兩層的B 樹可以儲存:16*1638=26208條資料;三層的B 樹可以儲存:16*1638*1638=42928704條資料。

MySQL的索引為什麼要使用B 樹而不使用跳表?

B 樹是多叉樹結構,每個結點都是16k的資料頁,能存放較多索引信息,所以扇出很高三層左右就可以儲存2kw左右的資料。也就是說查詢一次數據,如果這些數據頁都在磁碟裡,那麼最多需要查詢三次磁碟IO

跳表是鍊錶結構,一條數據一個結點,如果最底層要存放2kw數據,且每次查詢都要能達到二分查找的效果,2kw大概在2的24次方左右,所以,跳表大概高度在24層左右。最壞情況下,這24層資料會分散在不同的資料頁裡,也即是查一次資料會經歷24次磁碟IO

因此存放同樣量級的數據,B 樹的高度比跳表的要少,如果放在MySQL資料庫上來說,就是磁碟IO次數更少,因此B 樹查詢更快

而針對寫入操作,B 樹需要拆分合併索引資料頁,跳表則獨立插入,並根據隨機函數確定層數,沒有旋轉和維持平衡的開銷,因此跳表的寫入效能會比B 樹好。

其實,MySQL的儲存引擎是可以換的,以前mysql 5.5是myisam,後來才有的innodb,它們底層索引用的都是B 樹。也就是說,你完全可以造一個索引為跳表的儲存引擎裝到MySQL裡。事實上,facebook造了一個rocksDB的儲存引擎,裡面就用了跳表。直接說結論,它的寫入效能確實是比innodb好,但讀取效能確實比innodb要差不少。有興趣的話,可以在文章最後面的參考資料裡看到他們的效能比較數據。

Redis為什麼要使用跳表而不使用B 樹或二元樹呢?

因為B 樹的原理是葉子節點儲存數據,非葉子節點儲存索引,B 樹的每個節點可以儲存多個關鍵字,它將節點大小設為磁碟頁的大小,充分利用了磁碟預讀的功能。每次讀取磁碟頁時就會讀取一整個節點,每個葉子節點還有指向前後節點的指針,為的是最大限度的降低磁碟的IO。因為資料在記憶體中讀取耗費的時間是從磁碟的IO讀取的百萬分之一,而Redis是 記憶體中操作數據,不涉及IO,因此使用了跳表;

建立索引需要注意些什麼?

這題,也可以用在問你會哪些SQL優化的時候。

  • 最適合索引的欄位是出現在WHERE 子句中的列,或連接子句中的列,而不是出現在SELECT 關鍵字後的欄位。
  • 索引列的基底數越大,索引效果越好。
  • 根據情況建立複合索引,複合索引可以提高查詢效率。
  • 避免建立過多的索引,索引會額外佔用磁碟空間,降低寫入作業效率。
  • 主鍵盡可能選擇較短的資料類型,可以有效減少索引的磁碟佔用以提高查詢效率。
  • 對字串進行索引,應該自訂一個前綴長度,可以節省大量的索引空間。

如果單表資料量過千萬,怎麼優化?

1、資料庫設計和表格建立時,考慮效能問題,例如:單表不要有太多字段,建議在20以內、索引並不是越多越好,要根據查詢有針對性的創建,考慮在WHERE和ORDER BY命令上涉及的列建立索引,可根據EXPLAIN來查看是否用了索引還是全表掃描、選擇合適的資料類型、選擇合適索引類型等。

2、SQL寫時要注意,例如:清單資料不要拿全表,要使用LIMIT來分頁,每頁數量也不要太大、可透過開啟慢查詢日誌來找出較慢的SQL 、避免select *,將需要尋找的欄位列出來等。

3,儲存引擎選擇,MyISAM適合SELECT密集的表,而InnoDB適合INSERT和UPDATE密集的表

4、分庫分錶,例如:分庫把一個資料庫分成多個,建議做個讀寫分離就行了,真正的做分庫也會帶來大量的開發成本,得不償失!不建議使用、分錶就是把一張大表,按照如上過程都優化了,還是查詢卡死,那就把這個表分成多張表,把一次查詢分成多次查詢,然後把結果組合回傳給使用者。分錶分為垂直拆分和水平拆分,通常以某個欄位做拆分項。例如以id字段拆分為100張表:表名為 tableName_id 0。但:分錶需要修改原始程式碼,會為開發帶來大量工作,極大的增加了開發成本,故:只適合在開發初期就考慮到了大量資料存在,做好了分錶處理,不適合應用上線了再做修改,成本太高等。

5、硬體升級,這辦法是最簡單的,相對的成本也高,老闆就不願意了。

6、資料庫升級,例如:把MySQL資料庫換成大數據引擎處理資料、換成阿里雲POLARDB,POLARDB 是阿里雲自研的下一代關係式分散式雲端原生資料庫,100%相容MySQL,存儲容量最高可達100T,效能最高提升至MySQL 的6 倍。

一個500w條資料的表a,一個300w資料的表b,透過外鍵tid 關聯,如何最快的查詢出滿足條件的第50000到第50200中的這200筆數據記錄?

方法一:若 a 表 tid 是自增長,且是連續的,則以b表的id為索引。 SQL語句如下。

select * from a,b where a.tid = b.id and a.tid>500000 limit 200;

方法二:如果 a 表的 tid 不是連續的,那麼就需要使用覆蓋索引,tid 要麼是主鍵,要麼是輔助索引,b 表 id 也需要有索引。 SQL語句如下。

select * from b, (select tid from a limit 50000,200) a where b.id = a.tid;

說JVM的記憶體模型

#JVM記憶體結構有:程式計數器、堆疊記憶體、方法區和堆疊(java虛擬機棧和本地方法棧)。

程式計數器(Program Counter Register)是一塊較小的記憶體空間,它的作用可以看做是目前執行緒所執行的字節碼的行號指示器。在虛擬機器的概念模型裡(僅是概念模型,各種虛擬機器可能會透過一些更有效率的方式去實現),字節碼解釋器工作時就是透過改變這個計數器的值來選取下一條需要執行的字節碼指令,分支、循環、跳躍、異常處理、線程恢復等基礎功能都需要依賴這個計數器來完成。

堆記憶體是JVM中最大的一塊由年輕代和老年代組成,而年輕代內存又被分成三部分, Eden空間、 From Survivor空間、 To Survivor空間,默認情況下年輕代按照8:1:1 的比例來分配;

方法區儲存類別資訊、常數、靜態變數等數據,是執行緒共享的區域,為與Java堆區分,方法區還有一個別名Non-Heap(非堆);堆疊又分為java虛擬機器棧和本地方法棧主要用於方法的執行。方法區可理解為一種規範,其實現例如永久代、元空間。

Java虛擬機器堆疊(Java Virtual Machine Stacks)也是執行緒私有的,它的生命週期與執行緒相同。虛擬機器堆疊描述的是Java方法執行的記憶體模型:每個方法執行的時候都會同時建立一個堆疊幀(Stack Frame)用於儲存局部變數表、操作堆疊、動態連結、方法出口等信息。每一個方法被呼叫直到執行完成的過程,就對應一個堆疊幀在虛擬機器棧中從入棧到出棧的過程。

本機方法堆疊(Native Method Stacks)與虛擬機器堆疊所扮演的角色是非常相似的,其差異不過是虛擬機器堆疊為虛擬機器執行Java方法(也就是字節碼)服務,而本地方法堆疊則是為虛擬機器使用到的Native方法服務。 虛擬機器規範中對本機方法堆疊中的方法所使用的語言、使用方式與資料結構並沒有強制規定,因此具體的虛擬機器可以自由實作它。

為什麼需要Survivor區?

如果沒有Survivor,Eden區每進行一次Minor GC ,並且沒有年齡限制的話, 存活的對象就會被送到老年代。這樣一來,老年代很快就被填滿,觸發Major GC(因為Major GC一般伴隨著Minor GC,也可以看做觸發了Full GC)。舊年代的記憶體空間遠大於新生代,進行一次Full GC消耗的時間比Minor GC長很多。

面試官可能會問:執行時間長有什麼壞處?

#頻傳的Full GC消耗的時間很長,會影響大型程式的執行與回應速度。

如果增加老年代空間,更多存活物才能填滿老年代。雖然降低Full GC頻率,但是隨著老年代空間加大,一旦發生Full GC,執行所需的時間更長。

假如減少老年空間,雖然Full GC所需時間減少,但是老年代很快就被存活物件填滿,Full GC頻率增加。

所以Survivor的存在意義,就是減少被送到老年代的對象,進而減少Full GC的發生,Survivor的預篩選保證,只有經歷16 次Minor GC還能在新生代中存活的對象,才會被送到老年代。

你有什麼想問我的嗎?

這問題有的面試官是禮貌性的問,也不是很注意你回答什麼,因為此時估計面試就是涼涼啦。

但是,有反問的機會,大部分還是覺得你不錯,被錄取的機率非常大,所以還是得慎重回答

不管ta是怎麼樣的心態,咱們表現好自己就行。

這個問題看起來可有可無,其實很關鍵,一般面試官不喜歡說「沒問題」的人,因為其很注重員工的個性和創新能力。企業不喜歡求職者問個人福利之類的問題,如果有人這樣問:貴公司對新入公司的員工有沒有什麼培訓項目,我可以參加嗎?或者說貴公司的晉升機制是什麼樣的?企業將很歡迎,因為體現出你對學習的熱情和對公司的忠誠度以及你的上進心。

以上是順豐科技面試的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:Java后端技术全栈。如有侵權,請聯絡admin@php.cn刪除