【備戰春招/秋招系列】美團面經總結基礎篇 (附詳解答案)
該文已加入開源文件:JavaGuide(一份涵蓋大部分Java程式設計師所需要掌握的核心知識)。地址:github.com/Snailclimb/….
【強烈推薦!非廣告!】阿里雲雙11褥羊毛活動:m.aliyun.com/act/team111… 差不多一折,不過僅限阿里雲新人購買,不是新人的朋友自己找方法買哦!
系列文章:
這是我總結的美團面經的基礎篇,後面還有進階和終結篇哦!下面只是我從很多份美團面經中總結的在面試中一些常見的問題。不同於個人面經,這份面經具有普適性。每次面試必備的自我介紹、專案介紹這些東西,大家可以自己私下好好思考。我在前面的文章中也提到了應該怎麼做自我介紹與專案介紹,詳情可以檢視這篇文章:
1. System.out.println(3 | 9);
輸出什麼?
正確答案:11.
考察知識點:邏輯運算子與(&和&&)或(|和||)
&和&&:
共同點:它們都表示運算子的兩邊都是true時,結果為true;
不同點: & 表示在運算時兩邊都會計算,然後再判斷;&&表示先運算子號左邊的東西,然後判斷是否為true,是true就繼續運算右邊的然後判斷並輸出,是false就停下來直接輸出不會再執行後面的東西。
|和||:
共同點:它們都表示運算子的兩邊任意一邊為true,結果為true,兩邊都不是true,結果就為false;
不同點:| 表示兩邊都會運算,然後再判斷結果;|| 表示先運算子號左邊的東西,然後判斷是否為true,是true就停下來直接輸出不會再執行後面的東西,是false就繼續運算右邊的然後判斷並輸出。
回到本題:
3 | 9=0011(二進位制) | 1001(二進位制)=1011(二進位制)=11(十進位制)
2. 說一下轉發(Forward)和重定向(Redirect)的區別
轉發是伺服器行為,重定向是客戶端行為。
轉發(Forword) 通過RequestDispatcher物件的forward(HttpServletRequest request,HttpServletResponse response)
RequestDispatcher
可以通過HttpServletRequest
的 getRequestDispatcher()
方法獲得。例如下面的程式碼就是跳轉到 login_success.jsp 頁面。
request.getRequestDispatcher("login_success.jsp").forward(request, response);
複製程式碼
重定向(Redirect) 是利用伺服器返回的狀態嗎來實現的。客戶端瀏覽器請求伺服器的時候,伺服器會返回一個狀態碼。伺服器通過HttpServletRequestResponse的setStatus(int status)方法設定狀態碼。如果伺服器返回301或者302,則瀏覽器會到新的網址重新請求該資源。
- 從位址列顯示來說: forward是伺服器請求資源,伺服器直接訪問目標地址的URL,把那個URL的響應內容讀取過來,然後把這些內容再發給瀏覽器.瀏覽器根本不知道伺服器傳送的內容從哪裡來的,所以它的位址列還是原來的地址. redirect是服務端根據邏輯,傳送一個狀態碼,告訴瀏覽器重新去請求那個地址.所以位址列顯示的是新的URL.
- 從資料共享來說: forward:轉發頁面和轉發到的頁面可以共享request裡面的資料. redirect:不能共享資料.
- 從運用地方來說: forward:一般用於使用者登陸的時候,根據角色轉發到相應的模組. redirect:一般用於使用者登出登陸時返回主頁面和跳轉到其它的網站等
- 從效率來說: forward:高. redirect:低.
3. 在瀏覽器中輸入url地址 ->> 顯示主頁的過程,整個過程會使用哪些協議
圖解(圖片來源:《圖解HTTP》):
總體來說分為以下幾個過程:
- DNS解析
- TCP連線
- 傳送HTTP請求
- 伺服器處理請求並返回HTTP報文
- 瀏覽器解析渲染頁面
- 連線結束
具體可以參考下面這篇文章:
4. TCP 三次握手和四次揮手
為了準確無誤地把資料送達目標處,TCP協議採用了三次握手策略。
漫畫圖解:
圖片來源:《圖解HTTP》
簡單示意圖:
- 客戶端–傳送帶有 SYN 標誌的資料包–一次握手–服務端
- 服務端–傳送帶有 SYN/ACK 標誌的資料包–二次握手–客戶端
- 客戶端–傳送帶有帶有 ACK 標誌的資料包–三次握手–服務端
為什麼要三次握手
三次握手的目的是建立可靠的通訊通道,說到通訊,簡單來說就是資料的傳送與接收,而三次握手最主要的目的就是雙方確認自己與對方的傳送與接收是正常的。
第一次握手:Client 什麼都不能確認;Server 確認了對方傳送正常,自己接收正常。
第二次握手:Client 確認了:自己傳送、接收正常,對方傳送、接收正常;Server 確認了:自己接收正常,對方傳送正常
第三次握手:Client 確認了:自己傳送、接收正常,對方傳送、接收正常;Server 確認了:自己傳送、接收正常,對方傳送接收正常
所以三次握手就能確認雙發收發功能都正常,缺一不可。
為什麼要傳回 SYN
接收端傳回傳送端所傳送的 SYN 是為了告訴傳送端,我接收到的資訊確實就是你所傳送的訊號了。
SYN 是 TCP/IP 建立連線時使用的握手訊號。在客戶機和伺服器之間建立正常的 TCP 網路連線時,客戶機首先發出一個 SYN 訊息,伺服器使用 SYN-ACK 應答表示接收到了這個訊息,最後客戶機再以 ACK(Acknowledgement[漢譯:確認字元 ,在資料通訊傳輸中,接收站發給傳送站的一種傳輸控制字元。它表示確認發來的資料已經接受無誤。 ])訊息響應。這樣在客戶機和伺服器之間才能建立起可靠的TCP連線,資料才可以在客戶機和伺服器之間傳遞。
傳了 SYN,為啥還要傳 ACK
雙方通訊無誤必須是兩者互相傳送資訊都無誤。傳了 SYN,證明發送方(主動關閉方)到接收方(被動關閉方)的通道沒有問題,但是接收方到傳送方的通道還需要 ACK 訊號來進行驗證。
斷開一個 TCP 連線則需要“四次揮手”:
- 客戶端-傳送一個 FIN,用來關閉客戶端到伺服器的資料傳送
- 伺服器-收到這個 FIN,它發回一 個 ACK,確認序號為收到的序號加1 。和 SYN 一樣,一個 FIN 將佔用一個序號
- 伺服器-關閉與客戶端的連線,傳送一個FIN給客戶端
- 客戶端-發回 ACK 報文確認,並將確認序號設定為收到序號加1
為什麼要四次揮手
任何一方都可以在資料傳送結束後發出連線釋放的通知,待對方確認後進入半關閉狀態。當另一方也沒有資料再發送的時候,則發出連線釋放通知,對方確認後就完全關閉了TCP連線。
舉個例子:A 和 B 打電話,通話即將結束後,A 說“我沒啥要說的了”,B回答“我知道了”,但是 B 可能還會有要說的話,A 不能要求 B 跟著自己的節奏結束通話,於是 B 可能又巴拉巴拉說了一通,最後 B 說“我說完了”,A 回答“知道了”,這樣通話才算結束。
上面講的比較概括,推薦一篇講的比較細緻的文章:blog.csdn.net/qzcsu/artic…
5. IP地址與MAC地址的區別
IP地址是指網際網路協議地址(Internet Protocol Address)IP Address的縮寫。IP地址是IP協議提供的一種統一的地址格式,它為網際網路上的每一個網路和每一臺主機分配一個邏輯地址,以此來遮蔽實體地址的差異。
MAC 地址又稱為實體地址、硬體地址,用來定義網路裝置的位置。網絡卡的實體地址通常是由網絡卡生產廠家寫入網絡卡的,具有全球唯一性。MAC地址用於在網路中唯一標示一個網絡卡,一臺電腦會有一或多個網絡卡,每個網絡卡都需要有一個唯一的MAC地址。
6. HTTP請求、響應報文格式
HTTP請求報文主要由請求行、請求頭部、請求正文3部分組成
HTTP響應報文主要由狀態行、響應頭部、響應正文3部分組成
詳細內容可以參考:blog.csdn.net/a19881029/a…
7. 為什麼要使用索引?索引這麼多優點,為什麼不對錶中的每一個列建立一個索引呢?索引是如何提高查詢速度的?說一下使用索引的注意事項?Mysql索引主要使用的兩種資料結構?什麼是覆蓋索引?
為什麼要使用索引?
- 通過建立唯一性索引,可以保證資料庫表中每一行資料的唯一性。
- 可以大大加快 資料的檢索速度(大大減少的檢索的資料量), 這也是建立索引的最主要的原因。
- 幫助伺服器避免排序和臨時表
- 將隨機IO變為順序IO
- 可以加速表和表之間的連線,特別是在實現資料的參考完整性方面特別有意義。
索引這麼多優點,為什麼不對錶中的每一個列建立一個索引呢?
- 當對錶中的資料進行增加、刪除和修改的時候,索引也要動態的維護,這樣就降低了資料的維護速度。
- 索引需要佔物理空間,除了資料表佔資料空間之外,每一個索引還要佔一定的物理空間,如果要建立聚簇索引,那麼需要的空間就會更大。
- 建立索引和維護索引要耗費時間,這種時間隨著資料量的增加而增加。
索引是如何提高查詢速度的?
將無序的資料變成相對有序的資料(就像查目錄一樣)
說一下使用索引的注意事項
- 避免 where 子句中對宇段施加函式,這會造成無法命中索引。
- 在使用InnoDB時使用與業務無關的自增主鍵作為主鍵,即使用邏輯主鍵,而不要使用業務主鍵。
- 將打算加索引的列設定為 NOT NULL ,否則將導致引擎放棄使用索引而進行全表掃描
- 刪除長期未使用的索引,不用的索引的存在會造成不必要的效能損耗 MySQL 5.7 可以通過查詢 sys 庫的 chema_unused_indexes 檢視來查詢哪些索引從未被使用
- 在使用 limit offset 查詢緩慢時,可以藉助索引來提高效能
Mysql索引主要使用的哪兩種資料結構?
- 雜湊索引:對於雜湊索引來說,底層的資料結構就是雜湊表,因此在絕大多數需求為單條記錄查詢的時候,可以選擇雜湊索引,查詢效能最快;其餘大部分場景,建議選擇BTree索引。
- BTree索引:Mysql的BTree索引使用的是B樹中的B+Tree。但對於主要的兩種儲存引擎(MyISAM和InnoDB)的實現方式是不同的。
更多關於索引的內容可以檢視我的這篇文章:【思維導圖-索引篇】搞定資料庫索引就是這麼簡單
什麼是覆蓋索引?
如果一個索引包含(或者說覆蓋)所有需要查詢的欄位的值,我們就稱 之為“覆蓋索引”。我們知道在InnoDB儲存引擎中,如果不是主鍵索引,葉子節點儲存的是主鍵+列值。最終還是要“回表”,也就是要通過主鍵再查詢一次,這樣就會比較慢。覆蓋索引就是把要查詢出的列和索引是對應的,不做回表操作!
8. 程序與執行緒的區別是什麼?程序間的幾種通訊方式說一下?執行緒間的幾種通訊方式知道不?
程序與執行緒的區別是什麼?
執行緒與程序相似,但執行緒是一個比程序更小的執行單位。一個程序在其執行的過程中可以產生多個執行緒。與程序不同的是同類的多個執行緒共享同一塊記憶體空間和一組系統資源,所以系統在產生一個執行緒,或是在各個執行緒之間作切換工作時,負擔要比程序小得多,也正因為如此,執行緒也被稱為輕量級程序。另外,也正是因為共享資源,所以執行緒中執行時一般都要進行同步和互斥。總的來說,程序和執行緒的主要差別在於它們是不同的作業系統資源管理方式。
程序間的幾種通訊方式說一下?
- 管道(pipe):管道是一種半雙工的通訊方式,資料只能單向流動,而且只能在具有血緣關係的程序間使用。程序的血緣關係通常指父子程序關係。管道分為pipe(無名管道)和fifo(命名管道)兩種,有名管道也是半雙工的通訊方式,但是它允許無親緣關係程序間通訊。
- 訊號量(semophore):訊號量是一個計數器,可以用來控制多個程序對共享資源的訪問。它通常作為一種鎖機制,防止某程序正在訪問共享資源時,其他程序也訪問該資源。因此,主要作為程序間以及同一程序內不同執行緒之間的同步手段。
- 訊息佇列(message queue):訊息佇列是由訊息組成的連結串列,存放在核心中 並由訊息佇列識別符號標識。訊息佇列克服了訊號傳遞資訊少,管道只能承載無格式位元組流以及緩衝區大小受限等缺點。訊息佇列與管道通訊相比,其優勢是對每個訊息指定特定的訊息型別,接收的時候不需要按照佇列次序,而是可以根據自定義條件接收特定型別的訊息。
- 訊號(signal):訊號是一種比較複雜的通訊方式,用於通知接收程序某一事件已經發生。
- 共享記憶體(shared memory):共享記憶體就是對映一段能被其他程序所訪問的記憶體,這段共享記憶體由一個程序建立,但多個程序都可以訪問,共享記憶體是最快的IPC方式,它是針對其他程序間的通訊方式執行效率低而專門設計的。它往往與其他通訊機制,如訊號量配合使用,來實現程序間的同步和通訊。
- 套接字(socket):套介面也是一種程序間的通訊機制,與其他通訊機制不同的是它可以用於不同及其間的程序通訊。
執行緒間的幾種通訊方式知道不?
1、鎖機制
- 互斥鎖:提供了以排它方式阻止資料結構被併發修改的方法。
- 讀寫鎖:允許多個執行緒同時讀共享資料,而對寫操作互斥。
- 條件變數:可以以原子的方式阻塞程序,直到某個特定條件為真為止。對條件測試是在互斥鎖的保護下進行的。條件變數始終與互斥鎖一起使用。
2、訊號量機制:包括無名執行緒訊號量與有名執行緒訊號量
3、訊號機制:類似於程序間的訊號處理。
執行緒間通訊的主要目的是用於執行緒同步,所以執行緒沒有象程序通訊中用於資料交換的通訊機制。
9. 為什麼要用單例模式?手寫幾種執行緒安全的單例模式?
簡單來說使用單例模式可以帶來下面幾個好處:
- 對於頻繁使用的物件,可以省略建立物件所花費的時間,這對於那些重量級物件而言,是非常可觀的一筆系統開銷;
- 由於 new 操作的次數減少,因而對系統記憶體的使用頻率也會降低,這將減輕 GC 壓力,縮短 GC 停頓時間。
懶漢式(雙重檢查加鎖版本)
public class Singleton {
//volatile保證,當uniqueInstance變數被初始化成Singleton例項時,多個執行緒可以正確處理uniqueInstance變數
private volatile static Singleton uniqueInstance;
private Singleton() {
}
public static Singleton getInstance() {
//檢查例項,如果不存在,就進入同步程式碼塊
if (uniqueInstance == null) {
//只有第一次才徹底執行這裡的程式碼
synchronized(Singleton.class) {
//進入同步程式碼塊後,再檢查一次,如果仍是null,才建立例項
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
return uniqueInstance;
}
}
複製程式碼
靜態內部類方式
靜態內部實現的單例是懶載入的且執行緒安全。
只有通過顯式呼叫 getInstance 方法時,才會顯式裝載 SingletonHolder 類,從而例項化 instance(只有第一次使用這個單例的例項的時候才載入,同時不會有執行緒安全問題)。
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
複製程式碼
10. 簡單介紹一下bean。知道Spring的bean的作用域與生命週期嗎?
在 Spring 中,那些組成應用程式的主體及由 Spring IOC 容器所管理的物件,被稱之為 bean。簡單地講,bean 就是由 IOC 容器初始化、裝配及管理的物件,除此之外,bean 就與應用程式中的其他物件沒有什麼區別了。而 bean 的定義以及 bean 相互間的依賴關係將通過配置元資料來描述。
Spring中的bean預設都是單例的,這些單例Bean在多執行緒程式下如何保證執行緒安全呢? 例如對於Web應用來說,Web容器對於每個使用者請求都建立一個單獨的Sevlet執行緒來處理請求,引入Spring框架之後,每個Action都是單例的,那麼對於Spring託管的單例Service Bean,如何保證其安全呢? Spring的單例是基於BeanFactory也就是Spring容器的,單例Bean在此容器內只有一個,Java的單例是基於 JVM,每個 JVM 內只有一個例項。
Spring的bean的生命週期以及更多內容可以檢視:一文輕鬆搞懂Spring中bean的作用域與生命週期
11. Spring 中的事務傳播行為了解嗎?TransactionDefinition 介面中哪五個表示隔離級別的常量?
事務傳播行為
事務傳播行為(為了解決業務層方法之間互相呼叫的事務問題): 當事務方法被另一個事務方法呼叫時,必須指定事務應該如何傳播。例如:方法可能繼續在現有事務中執行,也可能開啟一個新事務,並在自己的事務中執行。在TransactionDefinition定義中包括瞭如下幾個表示傳播行為的常量:
支援當前事務的情況:
- TransactionDefinition.PROPAGATION_REQUIRED: 如果當前存在事務,則加入該事務;如果當前沒有事務,則建立一個新的事務。
- TransactionDefinition.PROPAGATION_SUPPORTS: 如果當前存在事務,則加入該事務;如果當前沒有事務,則以非事務的方式繼續執行。
- TransactionDefinition.PROPAGATION_MANDATORY: 如果當前存在事務,則加入該事務;如果當前沒有事務,則丟擲異常。(mandatory:強制性)
不支援當前事務的情況:
- TransactionDefinition.PROPAGATION_REQUIRES_NEW: 建立一個新的事務,如果當前存在事務,則把當前事務掛起。
- TransactionDefinition.PROPAGATION_NOT_SUPPORTED: 以非事務方式執行,如果當前存在事務,則把當前事務掛起。
- TransactionDefinition.PROPAGATION_NEVER: 以非事務方式執行,如果當前存在事務,則丟擲異常。
其他情況:
- TransactionDefinition.PROPAGATION_NESTED: 如果當前存在事務,則建立一個事務作為當前事務的巢狀事務來執行;如果當前沒有事務,則該取值等價於TransactionDefinition.PROPAGATION_REQUIRED。
隔離級別
TransactionDefinition 介面中定義了五個表示隔離級別的常量:
- TransactionDefinition.ISOLATION_DEFAULT: 使用後端資料庫預設的隔離級別,Mysql 預設採用的 REPEATABLE_READ隔離級別 Oracle 預設採用的 READ_COMMITTED隔離級別.
- TransactionDefinition.ISOLATION_READ_UNCOMMITTED: 最低的隔離級別,允許讀取尚未提交的資料變更,可能會導致髒讀、幻讀或不可重複讀
- TransactionDefinition.ISOLATION_READ_COMMITTED: 允許讀取併發事務已經提交的資料,可以阻止髒讀,但是幻讀或不可重複讀仍有可能發生
- TransactionDefinition.ISOLATION_REPEATABLE_READ: 對同一欄位的多次讀取結果都是一致的,除非資料是被本身事務自己所修改,可以阻止髒讀和不可重複讀,但幻讀仍有可能發生。
- TransactionDefinition.ISOLATION_SERIALIZABLE: 最高的隔離級別,完全服從ACID的隔離級別。所有的事務依次逐個執行,這樣事務之間就完全不可能產生干擾,也就是說,該級別可以防止髒讀、不可重複讀以及幻讀。但是這將嚴重影響程式的效能。通常情況下也不會用到該級別。
12. SpringMVC 原理了解嗎?
客戶端傳送請求-> 前端控制器 DispatcherServlet 接受客戶端請求 -> 找到處理器對映 HandlerMapping 解析請求對應的 Handler-> HandlerAdapter 會根據 Handler 來呼叫真正的處理器開處理請求,並處理相應的業務邏輯 -> 處理器返回一個模型檢視 ModelAndView -> 檢視解析器進行解析 -> 返回一個檢視物件->前端控制器 DispatcherServlet 渲染資料(Moder)->將得到檢視物件返回給使用者
關於 SpringMVC 原理更多內容可以檢視我的這篇文章:SpringMVC 工作原理詳解
13. Spring AOP IOC 實現原理
過了秋招挺長一段時間了,說實話我自己也忘了如何簡要概括 Spring AOP IOC 實現原理,就在網上找了一個較為簡潔的答案,下面分享給各位。
IOC: 控制反轉也叫依賴注入。IOC利用java反射機制,AOP利用代理模式。IOC 概念看似很抽象,但是很容易理解。說簡單點就是將物件交給容器管理,你只需要在spring配置檔案中配置對應的bean以及設定相關的屬性,讓spring容器來生成類的例項物件以及管理物件。在spring容器啟動的時候,spring會把你在配置檔案中配置的bean都初始化好,然後在你需要呼叫的時候,就把它已經初始化好的那些bean分配給你需要呼叫這些bean的類。
AOP: 面向切面程式設計。(Aspect-Oriented Programming) 。AOP可以說是對OOP的補充和完善。OOP引入封裝、繼承和多型性等概念來建立一種物件層次結構,用以模擬公共行為的一個集合。實現AOP的技術,主要分為兩大類:一是採用動態代理技術,利用擷取訊息的方式,對該訊息進行裝飾,以取代原有物件行為的執行;二是採用靜態織入的方式,引入特定的語法建立“方面”,從而使得編譯器可以在編譯期間織入有關“方面”的程式碼,屬於靜態代理。
你若盛開,清風自來。 歡迎關注我的微信公眾號:“Java面試通關手冊”,一個有溫度的微信公眾號。公眾號後臺回覆關鍵字“1”,可以免費獲取一份我精心準備的小禮物哦!