[ Java面試題 ]Java 開發崗面試知識點解析

Kevin.ZhangCG發表於2021-06-04

如背景中介紹,作者在一年之內參加過多場面試,應聘崗位均為 Java 開發方向。

在不斷的面試中,分類總結了 Java 開發崗位面試中的一些知識點。

主要包括以下幾個部分:

  1. Java 基礎知識點

  2. Java 常見集合

  3. 高併發程式設計(JUC 包)

  4. JVM 記憶體管理

  5. Java 8 知識點

  6. 網路協議相關

  7. 資料庫相關

  8. MVC 框架相關

  9. 大資料相關

  10. Linux 命令相關

面試,是大家從學校走向社會的第一步。

網際網路公司的校園招聘,從形式上說,面試一般分為 2-3 輪技術面試 +1 輪 HR 面試。

但是一些公司確實是沒有 HR 面試的,直接就是三輪技術面。

技術面試中,面試官一般會先就你所應聘的崗位進行相關知識的考察,也叫基礎知識和業務邏輯面試。

只要你回答的不是特別差,面試官通常會說:“我們們寫個程式碼吧”,這個時候就開始了演算法面試。

也就是說,一輪技術面試 = 基礎知識和業務邏輯面試 + 演算法面試。

關於演算法面試的總結,各位可以查閱我先前交流的 Chat:“知名網際網路公司校招中常見的演算法題”。

本文我們主要從技術面試聊起。技術面試包括:業務邏輯和基礎知識面試。

首先是業務邏輯面試 ,也就是講專案。

面試官會對你簡歷上寫的若干個專案其中之一拿出來和你聊聊。在期間,會針對你所做的東西進行深度挖掘。

 包括:為什麼要這麼做?優缺點分析,假如重新讓你做一次,你打算怎麼做? 等等。這個環節主要考察我們對自己做過的專案(實習專案或者校內專案)是否有一個清晰的認識。

關於業務邏輯面試的準備,建議在平時多多思考總結,對專案的資料來源、整體執行框架都應該熟悉掌握。

比如說你在某公司實習過程中,就可以進行總結,而不必等到快離職的時候慌慌張張的去總結該專案。

接下來是基礎知識面試。

Java 開發屬於後臺開發方向,有人說後臺開發很坑,因為需要學習的東西太多了。沒錯,這個崗位就是需要學習好多東西。

包括:本語言(Java/C++/PHP)基礎、資料庫、網路協議、Linux 系統、計算機原理甚至前端相關知識都可以考察你,而且,並不超綱 。

有時候,你報的是後臺開發崗,並且熟悉的是 Java 語言,但是面試官卻是 C++ 開發方向的,就是這麼無奈~

好了,閒話少說,讓我們開始分類講解常見面試知識點。

 

Java 基礎知識

01. 物件導向的特性有哪些?

答:封裝、繼承和多型。

物件導向程式設計的正確姿勢

02. Java 中覆蓋和過載是什麼意思?

解析:覆蓋和過載是比較重要的基礎知識點,並且容易混淆,所以面試中常見。

答:覆蓋(Override)是指子類對父類方法的一種重寫,只能比父類丟擲更少的異常,訪問許可權不能比父類的小。

被覆蓋的方法不能是 private 的,否則只是在子類中重新定義了一個方法;過載(Overload)表示同一個類中可以有多個名稱相同的方法,但這些方法的引數列表各不相同。

面試官: 那麼構成過載的條件有哪些?

答:引數型別不同、引數個數不同、引數順序不同。

面試官: 函式的返回值不同可以構成過載嗎?為什麼?

答:不可以,因為 Java 中呼叫函式並不需要強制賦值。舉例如下:

如下兩個方法:

    void f(){}    int f(){ return 1;}

只要編譯器可以根據語境明確判斷出語義,比如在 int x = f();中,那麼的確可以據此區分過載方法。

不過, 有時你並不關心方法的返回值,你想要的是方法呼叫的其他效果 (這常被稱為 “為了副作用而呼叫”),這時你可能會呼叫方法而忽略其返回值,所以如果像下面的呼叫:

    fun();

此時 Java 如何才能判斷呼叫的是哪一個 f( ) 呢?別人如何理解這種程式碼呢?所以,根據方法返回值來區分過載方法是行不通的。

03. 抽象類和介面的區別有哪些?

Java 抽象類與介面

答:

  1. 抽象類中可以沒有抽象方法;介面中的方法必須是抽象方法;

  2. 抽象類中可以有普通的成員變數;介面中的變數必須是 static final 型別的,必須被初始化 , 介面中只有常量,沒有變數。

  3. 抽象類只能單繼承,介面可以繼承多個父介面;

  4. Java8 中介面中會有 default 方法,即方法可以被實現。

面試官:抽象類和介面如何選擇?

答:

  1. 如果要建立不帶任何方法定義和成員變數的基類,那麼就應該選擇介面而不是抽象類。

  2. 如果知道某個類應該是基類,那麼第一個選擇的應該是讓它成為一個介面,只有在必須要有方法定義和成員變數的時候,才應該選擇抽象類。

    因為抽象類中允許存在一個或多個被具體實現的方法,只要方法沒有被全部實現該類就仍是抽象類。

04. Java 和 C++ 的區別:

解析:雖然我們不太懂 C++,但是就是會這麼問,尤其是三面(總監級別)面試中。

答:

  1. 都是物件導向的語言,都支援封裝、繼承和多型;

  2. 指標:Java 不提供指標來直接訪問記憶體,程式更加安全;

  3. 繼承: Java 的類是單繼承的,C++ 支援多重繼承; Java 通過一個類實現多個介面來實現 C++ 中的多重繼承; Java 中類不可以多繼承,但是!!!介面可以多繼承;

  4. 記憶體: Java 有自動記憶體管理機制,不需要程式設計師手動釋放無用記憶體。

05. Java 中的值傳遞和引用傳遞

答:

值傳遞是指物件被值傳遞,意味著傳遞了物件的一個副本,即使副本被改變,也不會影響源物件。引用傳遞是指物件被引用傳遞,意味著傳遞的並不是實際的物件,而是物件的引用。

因此,外部對引用物件的改變會反映到所有的物件上。

06. JDK 中常用的包有哪些?

答:java.lang、java.util、java.io、java.net、java.sql。

07. JDK,JRE 和 JVM 的聯絡和區別:

答:

JDK 是 java 開發工具包,是 java 開發環境的核心元件,並提供編譯、除錯和執行一個 java 程式所需要的所有工具,可執行檔案和二進位制檔案,是一個平臺特定的軟體。

JRE 是 java 執行時環境,是 JVM 的實施實現,提供了執行 java 程式的平臺。JRE 包含了 JVM,但是不包含 java 編譯器 / 偵錯程式之類的開發工具。

JVM 是 java 虛擬機器,當我們執行一個程式時,JVM 負責將位元組碼轉換為特定機器程式碼,JVM 提供了記憶體管理 / 垃圾回收和安全機制等。

JVM 垃圾回收機制

這種獨立於硬體和作業系統,正是 java 程式可以一次編寫多處執行的原因。

區別:

  1. JDK 用於開發,JRE 用於執行 java 程式;

  2. JDK 和 JRE 中都包含 JVM;

  3. JVM 是 java 程式語言的核心並且具有平臺獨立性。

小結:本節主要闡述了 Java 基礎知識點,這些問題主要是一面面試官在考察,難度不大,適當複習下,應該沒什麼問題。

 

Java 中常見集合

 

集合這方面的考察相當多,這部分是面試中必考的知識點。

01. 說說常見的集合有哪些吧?

答:

Map 介面和 Collection 介面是所有集合框架的父介面:

1. Collection 介面的子介面包括:Set 介面和 List 介面;

2. Map 介面的實現類主要有:HashMap、TreeMap、Hashtable、ConcurrentHashMap 以及 Properties 等;

3. Set 介面的實現類主要有:HashSet、TreeSet、LinkedHashSet 等;

4. List 介面的實現類主要有:ArrayList、LinkedList、Stack 以及 Vector 等。

02. HashMap 和 Hashtable 的區別有哪些?(必問)

答:

  1. HashMap 沒有考慮同步,是執行緒不安全的;Hashtable 使用了 synchronized 關鍵字,是執行緒安全的;

  2. 前者允許 null 作為 Key;後者不允許 null 作為 Key。

03. HashMap 的底層實現你知道嗎?

答:

在 Java8 之前,其底層實現是陣列 + 連結串列實現,Java8 使用了陣列 + 連結串列 + 紅黑樹實現。此時你可以簡單的在紙上畫圖分析:

04. ConcurrentHashMap 和 Hashtable 的區別? (必問)

答:

ConcurrentHashMap 結合了 HashMap 和 HashTable 二者的優勢。

HashMap 沒有考慮同步,hashtable 考慮了同步的問題。但是 hashtable 在每次同步執行時都要鎖住整個結構。

ConcurrentHashMap 鎖的方式是稍微細粒度的。 ConcurrentHashMap 將 hash 表分為 16 個桶(預設值),諸如 get,put,remove 等常用操作只鎖當前需要用到的桶。

面試官:ConcurrentHashMap 的具體實現知道嗎?

答:

  1. 該類包含兩個靜態內部類 HashEntry 和 Segment;前者用來封裝對映表的鍵值對,後者用來充當鎖的角色;

  2. Segment 是一種可重入的鎖 ReentrantLock,每個 Segment 守護一個 HashEntry 陣列裡得元素,當對 HashEntry 陣列的資料進行修改時,必須首先獲得對應的 Segment 鎖。

05. HashMap 的長度為什麼是 2 的冪次方?

答:

  1. 通過將 Key 的 hash 值與 length-1 進行 & 運算,實現了當前 Key 的定位,2 的冪次方可以減少衝突(碰撞)的次數,提高 HashMap 查詢效率;

  2. 如果 length 為 2 的次冪  則 length-1 轉化為二進位制必定是 11111……的形式,在於 h 的二進位制與操作效率會非常的快,而且空間不浪費;

  3. 如果 length 不是 2 的次冪,比如 length 為 15,則 length-1 為 14,對應的二進位制為 1110,在於 h 與操作,最後一位都為 0,而 0001,0011,0101,1001,1011,0111,1101 這幾個位置永遠都不能存放元素了,空間浪費相當大。

    更糟的是這種情況中,陣列可以使用的位置比陣列長度小了很多,這意味著進一步增加了碰撞的機率,減慢了查詢的效率!這樣就會造成空間的浪費。

06. List 和 Set 的區別是啥?

答:List 元素是有序的,可以重複;Set 元素是無序的,不可以重複。

07. List、Set 和 Map 的初始容量和載入因子

答:

1. List

  • ArrayList 的初始容量是 10;載入因子為 0.5; 擴容增量:原容量的 0.5 倍 +1;一次擴容後長度為 16。

  • Vector 初始容量為 10,載入因子是 1。擴容增量:原容量的 1 倍,如 Vector 的容量為 10,一次擴容後是容量為 20。

2. Set

HashSet,初始容量為 16,載入因子為 0.75; 擴容增量:原容量的 1 倍; 如 HashSet 的容量為 16,一次擴容後容量為 32

3. Map

HashMap,初始容量 16,載入因子為 0.75; 擴容增量:原容量的 1 倍; 如 HashMap 的容量為 16,一次擴容後容量為 32

08. Comparable 介面和 Comparator 介面有什麼區別?

答:

  1. 前者簡單,但是如果需要重新定義比較型別時,需要修改原始碼。

  2. 後者不需要修改原始碼,自定義一個比較器,實現自定義的比較方法。

09. Java 集合的快速失敗機制 “fail-fast”

答:

它是 java 集合的一種錯誤檢測機制,當多個執行緒對集合進行結構上的改變的操作時,有可能會產生 fail-fast 機制。

例如 :假設存在兩個執行緒(執行緒 1、執行緒 2),執行緒 1 通過 Iterator 在遍歷集合 A 中的元素,在某個時候執行緒 2 修改了集合 A 的結構(是結構上面的修改,而不是簡單的修改集合元素的內容),那麼這個時候程式就會丟擲 ConcurrentModificationException 異常,從而產生 fail-fast 機制。

原因: 迭代器在遍歷時直接訪問集合中的內容,並且在遍歷過程中使用一個 modCount 變數。集合在被遍歷期間如果內容發生變化,就會改變 modCount 的值。

每當迭代器使用 hashNext()/next() 遍歷下一個元素之前,都會檢測 modCount 變數是否為 expectedmodCount 值,是的話就返回遍歷;否則丟擲異常,終止遍歷。

解決辦法:

  1. 在遍歷過程中,所有涉及到改變 modCount 值得地方全部加上 synchronized;

  2. 使用 CopyOnWriteArrayList 來替換 ArrayList。

小結:本小節是 Java 中關於集合的考察,是 Java 崗位面試中必考的知識點,除了應該掌握以上的問題,包括各個集合的底層實現也建議各位同學閱讀,加深理解。

 

高併發程式設計

在 Java 5.0 提供了 java.util.concurrent(簡稱 JUC )包,在此包中增加了在併發程式設計中很常用的實用工具類,用於定義類似於執行緒的自定義子系統,包括執行緒池、非同步 IO 和輕量級任務框架。

01. 多執行緒和單執行緒的區別和聯絡:

答:

  1. 在單核 CPU 中,將 CPU 分為很小的時間片,在每一時刻只能有一個執行緒在執行,是一種微觀上輪流佔用 CPU 的機制。

  2. 多執行緒會存線上程上下文切換,會導致程式執行速度變慢,即採用一個擁有兩個執行緒的程式執行所需要的時間比一個執行緒的程式執行兩次所需要的時間要多一些。

結論:即採用多執行緒不會提高程式的執行速度,反而會降低速度,但是對於使用者來說,可以減少使用者的響應時間。

02. 如何指定多個執行緒的執行順序?

解析:面試官會給你舉個例子,如何讓 10 個執行緒按照順序列印 0123456789?(寫程式碼實現)

答:

  1. 設定一個 orderNum,每個執行緒執行結束之後,更新 orderNum,指明下一個要執行的執行緒。並且喚醒所有的等待執行緒。

  2. 在每一個執行緒的開始,要 while 判斷 orderNum 是否等於自己的要求值!!不是,則 wait,是則執行本執行緒。

03. 執行緒和程式的區別(必考)

答:

  1. 程式是一個 “執行中的程式”,是系統進行資源分配和排程的一個獨立單位;

  2. 執行緒是程式的一個實體,一個程式中擁有多個執行緒,執行緒之間共享地址空間和其它資源(所以通訊和同步等操作執行緒比程式更加容易);

  3. 執行緒上下文的切換比程式上下文切換要快很多。

  • (1)程式切換時,涉及到當前程式的 CPU 環境的儲存和新被排程執行程式的 CPU 環境的設定。

  • (2)執行緒切換僅需要儲存和設定少量的暫存器內容,不涉及儲存管理方面的操作。

04. 多執行緒產生死鎖的 4 個必要條件?

答:

  1. 互斥條件:一個資源每次只能被一個執行緒使用;

  2. 請求與保持條件:一個執行緒因請求資源而阻塞時,對已獲得的資源保持不放;

  3. 不剝奪條件:程式已經獲得的資源,在未使用完之前,不能強行剝奪;

  4. 迴圈等待條件:若干執行緒之間形成一種頭尾相接的迴圈等待資源關係。

面試官:如何避免死鎖?(經常接著問這個問題哦~)

答:指定獲取鎖的順序,舉例如下:

  1. 比如某個執行緒只有獲得 A 鎖和 B 鎖才能對某資源進行操作,在多執行緒條件下,如何避免死鎖?

  2. 獲得鎖的順序是一定的,比如規定,只有獲得 A 鎖的執行緒才有資格獲取 B 鎖,按順序獲取鎖就可以避免死鎖!!!

05. sleep( ) 和 wait( n)、wait( ) 的區別:

答:

  1. sleep 方法:是 Thread 類的靜態方法,當前執行緒將睡眠 n 毫秒,執行緒進入阻塞狀態。當睡眠時間到了,會解除阻塞,進行可執行狀態,等待 CPU 的到來。睡眠不釋放鎖(如果有的話);

  2. wait 方法:是 Object 的方法,必須與 synchronized 關鍵字一起使用,執行緒進入阻塞狀態,當 notify 或者 notifyall 被呼叫後,會解除阻塞。但是,只有重新佔用互斥鎖之後才會進入可執行狀態。睡眠時,釋放互斥鎖。

06. synchronized 關鍵字:

答:

底層實現:

  1. 進入時,執行 monitorenter,將計數器 +1,釋放鎖 monitorexit 時,計數器-1;

  2. 當一個執行緒判斷到計數器為 0 時,則當前鎖空閒,可以佔用;反之,當前執行緒進入等待狀態。

含義:(monitor 機制)

Synchronized 是在加鎖,加物件鎖。物件鎖是一種重量鎖(monitor),synchronized 的鎖機制會根據執行緒競爭情況在執行時會有偏向鎖(單一執行緒)、輕量鎖(多個執行緒訪問 synchronized 區域)、物件鎖(重量鎖,多個執行緒存在競爭的情況)、自旋鎖等。

該關鍵字是一個幾種鎖的封裝。

07. volatile 關鍵字

解析:關於指令重排序的問題,可以查閱 DCL 雙檢鎖失效相關資料。

答:

該關鍵字可以保證可見性不保證原子性。

功能:

  1. 主記憶體和工作記憶體,直接與主記憶體產生互動,進行讀寫操作,保證可見性;

  2. 禁止 JVM 進行的指令重排序。

08. ThreadLocal(執行緒區域性變數)關鍵字:

答:

當使用 ThreadLocal 維護變數時,其為每個使用該變數的執行緒提供獨立的變數副本,所以每一個執行緒都可以獨立的改變自己的副本,而不會影響其他執行緒對應的副本。

ThreadLocal 內部實現機制:

  1. 每個執行緒內部都會維護一個類似 HashMap 的物件,稱為 ThreadLocalMap,裡邊會包含若干了 Entry(K-V 鍵值對),相應的執行緒被稱為這些 Entry 的屬主執行緒;

  2. Entry 的 Key 是一個 ThreadLocal 例項,Value 是一個執行緒特有物件。Entry 的作用即是:為其屬主執行緒建立起一個 ThreadLocal 例項與一個執行緒特有物件之間的對應關係;

  3. Entry 對 Key 的引用是弱引用;Entry 對 Value 的引用是強引用。

09. Atomic 關鍵字:

答:可以使基本資料型別以原子的方式實現自增自減等操作。

10. 執行緒池有了解嗎?(必考)

答:

java.util.concurrent.ThreadPoolExecutor 類就是一個執行緒池。客戶端呼叫 ThreadPoolExecutor.submit(Runnable task) 提交任務,執行緒池內部維護的工作者執行緒的數量就是該執行緒池的執行緒池大小,有 3 種形態:

  • 當前執行緒池大小 :表示執行緒池中實際工作者執行緒的數量;

  • 最大執行緒池大小 (maxinumPoolSize):表示執行緒池中允許存在的工作者執行緒的數量上限;

  • 核心執行緒大小 (corePoolSize ):表示一個不大於最大執行緒池大小的工作者執行緒數量上限。

  1. 如果執行的執行緒少於 corePoolSize,則 Executor 始終首選新增新的執行緒,而不進行排隊;

  2. 如果執行的執行緒等於或者多於 corePoolSize,則 Executor 始終首選將請求加入佇列,而不是新增新執行緒;

  3. 如果無法將請求加入佇列,即佇列已經滿了,則建立新的執行緒,除非建立此執行緒超出 maxinumPoolSize, 在這種情況下,任務將被拒絕。

限於篇幅有限,更多高併發程式設計中的問題,請參考:

1.  Java 多執行緒程式設計核心技術

2. Java多執行緒與併發程式設計

小結:本小節內容涉及到 Java 中多執行緒程式設計,執行緒安全等知識,是面試中的重點和難點。

 

JVM 記憶體管理

 

既然是 Java 開發面試,那麼對 JVM 的考察當然也是必須的,面試官一般會問你對 JVM 有了解嗎?

我通常都會把我所瞭解的都說一遍,包括:JVM 記憶體劃分、JVM 垃圾回收的含義,有哪些 GC 演算法,年輕代和老年代各自的特點統統闡述一遍。

JVM 垃圾回收機制

01. JVM 記憶體劃分:

  1. 方法區(執行緒共享):常量、靜態變數、JIT(即時編譯器) 編譯後的程式碼也都在方法區;

  2. 堆記憶體(執行緒共享):垃圾回收的主要場所;

  3. 程式計數器: 當前執行緒執行的位元組碼的位置指示器;

  4. 虛擬機器棧(棧記憶體):儲存區域性變數、基本資料型別變數以及堆記憶體中某個物件的引用變數;

  5. 本地方法棧 :為 JVM 提供使用 native 方法的服務。

02. 類似-Xms、-Xmn 這些引數的含義:

答:

堆記憶體分配:

  1. JVM 初始分配的記憶體由-Xms 指定,預設是實體記憶體的 1/64;

  2. JVM 最大分配的記憶體由-Xmx 指定,預設是實體記憶體的 1/4;

  3. 預設空餘堆記憶體小於 40% 時,JVM 就會增大堆直到-Xmx 的最大限制;空餘堆記憶體大於 70% 時,JVM 會減少堆直到 -Xms 的最小限制;

  4. 因此伺服器一般設定-Xms、-Xmx 相等以避免在每次 GC 後調整堆的大小。物件的堆記憶體由稱為垃圾回收器的自動記憶體管理系統回收。

非堆記憶體分配:

  1. JVM 使用-XX:PermSize 設定非堆記憶體初始值,預設是實體記憶體的 1/64;

  2. 由 XX:MaxPermSize 設定最大非堆記憶體的大小,預設是實體記憶體的 1/4;

  3. -Xmn2G:設定年輕代大小為 2G;

  4. -XX:SurvivorRatio,設定年輕代中 Eden 區與 Survivor 區的比值。

03. 垃圾回收演算法有哪些?

答:

  1. 引用計數 :原理是此物件有一個引用,即增加一個計數,刪除一個引用則減少一個計數。垃圾回收時,只用收集計數為 0 的物件。此演算法最致命的是無法處理迴圈引用的問題;

  2. 標記-清除 :此演算法執行分兩階段。第一階段從引用根節點開始標記所有被引用的物件,第二階段遍歷整個堆,把未標記的物件清除;

    此演算法需要暫停整個應用,同時,會產生記憶體碎片;

  3. 複製演算法 :此演算法把記憶體空間劃為兩個相等的區域,每次只使用其中一個區域。垃圾回收時,遍歷當前使用區域,把正在使用中的物件複製到另外一個區域中;

    此演算法每次只處理正在使用中的物件,因此複製成本比較小,同時複製過去以後還能進行相應的記憶體整理,不會出現 “碎片” 問題。當然,此演算法的缺點也是很明顯的,就是需要兩倍記憶體空間;

  4. 標記-整理 :此演算法結合了 “標記-清除” 和 “複製” 兩個演算法的優點。也是分兩階段,第一階段從根節點開始標記所有被引用物件,第二階段遍歷整個堆,把清除未標記物件並且把存活物件 “壓縮” 到堆的其中一塊,按順序排放。

    此演算法避免了 “標記-清除” 的碎片問題,同時也避免了 “複製” 演算法的空間問題。

04. root 搜尋演算法中,哪些可以作為 root?

答:

  • 被啟動類(bootstrap 載入器)載入的類和建立的物件;

  • JavaStack 中的引用的物件 (棧記憶體中引用的物件);

  • 方法區中靜態引用指向的物件;

  • 方法區中常量引用指向的物件;

  • Native 方法中 JNI 引用的物件。

05. GC 什麼時候開始?

答:

GC 經常發生的區域是堆區,堆區還可以細分為新生代、老年代,新生代還分為一個 Eden 區和兩個 Survivor 區。

  1. 物件優先在 Eden 中分配,當 Eden 中沒有足夠空間時,虛擬機器將發生一次 Minor GC,因為 Java 大多數物件都是朝生夕滅,所以 Minor GC 非常頻繁,而且速度也很快;

  2. Full GC,發生在老年代的 GC,當老年代沒有足夠的空間時即發生 Full GC,發生 Full GC 一般都會有一次 Minor GC。

    大物件直接進入老年代,如很長的字串陣列,虛擬機器提供一個;XX:PretenureSizeThreadhold 引數,令大於這個引數值的物件直接在老年代中分配,避免在 Eden 區和兩個 Survivor 區發生大量的記憶體拷貝;

  3. 發生 Minor GC 時,虛擬機器會檢測之前每次晉升到老年代的平均大小是否大於老年代的剩餘空間大小,如果大於,則進行一次 Full GC,如果小於,則檢視 HandlePromotionFailure 設定是否允許擔保失敗,如果允許,那隻會進行一次 Minor GC,如果不允許,則改為進行一次 Full GC。

06. 記憶體洩漏和記憶體溢位

答:

概念:

  1. 記憶體溢位指的是記憶體不夠用了;

  2. 記憶體洩漏是指物件可達,但是沒用了。即本該被 GC 回收的物件並沒有被回收;

  3. 記憶體洩露是導致記憶體溢位的原因之一;記憶體洩露積累起來將導致記憶體溢位。

記憶體洩漏的原因分析:

  1. 長生命週期的物件引用短生命週期的物件;

  2. 沒有將無用物件置為 null。

小結:本小節涉及到 JVM 虛擬機器,包括對記憶體的管理等知識,相對較深。除了以上問題,面試官會繼續問你一些比較深的問題,可能也是為了看看你的極限在哪裡吧。

比如:記憶體調優、記憶體管理,是否遇到過記憶體洩漏的實際案例、是否真正關心過記憶體等。由於本人實際專案經驗不足,這些深層次問題並沒有接觸過,各位有需要可以上網查閱。

 

Java 8 相關知識

 

關於 Java8 中新知識點,面試官會讓你說說 Java8 你瞭解多少,下邊主要闡述我所瞭解,並且在面試中回答的 Java8 新增知識點。

0.1 HashMap 的底層實現有變化:HashMap 是陣列 + 連結串列 + 紅黑樹(JDK1.8 增加了紅黑樹部分)實現。

02. JVM 記憶體管理方面,由元空間代替了永久代。

區別:

1. 元空間並不在虛擬機器中,而是使用本地記憶體;

2. 預設情況下,元空間的大小僅受本地記憶體限制;

3. 也可以通過 -XX:MetaspaceSize 指定元空間大小。

03. Lambda 表示式(也稱為閉包),允許我們將函式當成引數傳遞給某個方法,或者把程式碼本身當做資料處理。

04. 函式式介面:指的是隻有一個函式的介面,java.lang.Runnable 和 java.util.concurrent.Callable 就是函式式介面的例子;java8 提供了一個特殊的註解 @Functionallnterface 來標明該介面是一個函式式介面。

05. 引入重複註解:Java 8 中使用 @Repeatable 註解定義重複註解。

06. 介面中可以實現方法 default 方法。

07. 註解的使用場景拓寬: 註解幾乎可以使用在任何元素上:區域性變數、介面型別、超類和介面實現類,甚至可以用在函式的異常定義上。

08. 新的包 java.time 包

  1. 包含了所有關於日期、時間、時區、持續時間和時鐘操作的類。(Java 8 的日期與時間問題解決方案

  2. 這些類都是不可變的、執行緒安全的。

小結:Java8 的一些新特性,面試官一般情況下不要求你有多麼精通,主要是看看你有沒有一些瞭解。

 

網路協議相關

 

網路協議方面,考察最多的包括伺服器和客戶端在三次握手、四次揮手過程中的狀態變化;還有網路擁塞控制,及其解決辦法等。

01. 三次握手、四次揮手示意圖:

總共有四種狀態:主動建立連線、主動斷開連線、被動建立連和被動斷開連線

兩兩組合還是 4 種組合:

  1. 主動建立連線、主動斷開連線會經歷的狀態:
    SYNC_SENT——ESTABLISHED—-FIN_WAIT_1—-FIN_WAIT_2—-TIME_WAIT

  2. 主動建立連線、被動斷開連線會經歷的狀態:
    SYNC_SENT——ESTABLISHED—-CLOSE_WAIT—-LAST_ACK

  3. 被動建立連線、主動斷開連線會經歷的狀態:
    LISTEN—-SYN_RCVD—-ESTABLISHED—-FIN_WAIT_1—-FIN_WAIT_2—-TIME_WAIT

  4. 被動建立連線、被動斷開連線會經歷的狀態:
    LISTEN—-SYN_RCVD—-ESTABLISHED—-CLOSE_WAIT—-LAST_ACK

02. 滑動視窗機制

由傳送方和接收方在三次握手階段,互相將自己的最大可接收的資料量告訴對方。

也就是自己的資料接收緩衝池的大小。這樣對方可以根據已傳送的資料量來計算是否可以接著傳送。

在處理過程中,當接收緩衝池的大小發生變化時,要給對方傳送更新視窗大小的通知。

03. 擁塞避免機制

擁塞:對資源的需求超過了可用的資源。若網路中許多資源同時供應不足,網路的效能就要明顯變壞,整個網路的吞吐量隨之負荷的增大而下降。

擁塞控制:防止過多的資料注入到網路中,使得網路中的路由器或鏈路不致過載。

擁塞控制方法:

  • 慢開始 + 擁塞避免;

  • 快重傳 + 快恢復。

04. 瀏覽器中輸入:“www.xxx.com” 之後都發生了什麼?請詳細闡述。

解析:經典的網路協議問題。

答:

  1. 由域名→IP 地址
    尋找 IP 地址的過程依次經過了瀏覽器快取、系統快取、hosts 檔案、路由器快取、 遞迴搜尋根域名伺服器。

  2. 建立 TCP/IP 連線(三次握手具體過程)

  3. 由瀏覽器傳送一個 HTTP 請求

  4. 經過路由器的轉發,通過伺服器的防火牆,該 HTTP 請求到達了伺服器

  5. 伺服器處理該 HTTP 請求,返回一個 HTML 檔案

  6. 瀏覽器解析該 HTML 檔案,並且顯示在瀏覽器端

  7. 這裡需要注意:

  • HTTP 協議是一種基於 TCP/IP 的應用層協議,進行 HTTP 資料請求必須先建立 TCP/IP 連線

  • 可以這樣理解:HTTP 是轎車,提供了封裝或者顯示資料的具體形式;Socket 是發動機,提供了網路通訊的能力。

  • 兩個計算機之間的交流無非是兩個埠之間的資料通訊 , 具體的資料會以什麼樣的形式展現是以不同的應用層協議來定義的。

05. 常見 HTTP 狀態碼

  1. 1xx(臨時響應)

  2. 2xx(成功)

  3. 3xx(重定向):表示要完成請求需要進一步操作

  4. 4xx(錯誤):表示請求可能出錯,妨礙了伺服器的處理

  5. 5xx(伺服器錯誤):表示伺服器在嘗試處理請求時發生內部錯誤

  6. 常見狀態碼:

  • 200(成功)

  • 304(未修改):自從上次請求後,請求的網頁未修改過。伺服器返回此響應時,不會返回網頁內容

  • 401(未授權):請求要求身份驗證

  • 403(禁止):伺服器拒絕請求

  • 404(未找到):伺服器找不到請求的網頁

06. TCP 和 UDP 的區別:

答:

  1. 回答傳送資料前是否存在建立連線的過程;

  2. TCP過確認機制,丟包可以重發,保證資料的正確性;UDP不保證正確性,只是單純的負責傳送資料包;

  3. UDP 是面向報文的。傳送方的 UDP 對應用程式交下來的報文,在新增首部後就向下交付給 IP 層。既不拆分,也不合並,而是保留這些報文的邊界,因 此,應用程式需要選擇合適的報文大小;

  4. UDP 的頭部,只有 8 個位元組,相對於 TCP 頭部的 20 個位元組資訊包的額外開銷很小。

限於篇幅,更多網路協議相關知識參考:

1. 如何快速入門網路基礎知識(TCP/IP 和 HTTP)

2. 圖解 HTTP

小結:必須熟練掌握 TCP 和 UDP 的區別、三次握手和四次揮手的狀態切換,必考

 

資料庫知識點

 

既然是後端開發,那麼與資料庫相關的知識點也是必不可少的。

01. MySQL 和 MongoDB 的區別有哪些?如何選擇?

02. MongoDB 的優缺點有哪些?

(ps 本人對這一塊不是很熟悉,就不附上參考答案了,請各位小夥伴自行學習哈~)

03. 聽說過事務嗎?(必考)

答:

作為單個邏輯工作單元執行的一系列操作,滿足四大特性:

  1. 原子性(Atomicity):事務作為一個整體被執行 ,要麼全部執行,要麼全部不執行;

  2. 一致性(Consistency):保證資料庫狀態從一個一致狀態轉變為另一個一致狀態;

  3. 隔離性(Isolation):多個事務併發執行時,一個事務的執行不應影響其他事務的執行;

  4. 永續性(Durability):一個事務一旦提交,對資料庫的修改應該永久儲存。

04. 事務的併發問題有哪幾種?

答:丟失更新、髒讀、不可重複讀以及幻讀。

05. 資料庫中的鎖有哪幾種?

答:獨佔鎖、排他鎖以及更新鎖。

06. 事務的隔離級別有哪幾種?

答:讀未提交、讀已提交、可重複讀和序列化。

擴充套件問題:MySQL 事務預設隔離級別是哪個?

答:可重複讀。

07. 資料庫的索引有什麼作用?(必考) 底層資料結構是什麼,為什麼使用這種資料結構?

答:

  1. 索引  是對資料庫表中一列或多列的值進行排序的一種結構,使用索引可快速訪問資料庫表中的特定資訊;

  2. 底層資料結構是 B+ 樹;

  3. 使用 B+ 樹的原因:查詢速度快、效率高,在查詢的過程中,每次都能拋棄掉一部分節點,減少遍歷個數。( 此時,你應該在白紙上畫出什麼是 B+ 樹 )

擴充套件問題:聚簇索引和非聚簇索引的區別?

08. MyISAM 和 InnoDB 的區別有哪些?

答:

  • MyISAM 不支援事務,InnoDB 是事務型別的儲存引擎;

  • MyISAM 只支援表級鎖,BDB 支援頁級鎖和表級鎖,預設為頁級鎖;而 InnoDB 支援行級鎖和表級鎖,預設為行級鎖;

  • MyISAM 引擎不支援外來鍵,InnoDB 支援外來鍵;

  • MyISAM 引擎的表在大量高併發的讀寫下會經常出現表損壞的情況;

  • 對於 count( ) 查詢來說 MyISAM 更有優勢;

  • InnoDB 是為處理巨大資料量時的最大效能設計,它的 CPU 效率可能是任何其它基於磁碟的關聯式資料庫引擎所不能匹敵的;

  • MyISAM 支援全文索引(FULLTEXT),InnoDB 不支援;

  • MyISAM 引擎的表的查詢、更新、插入的效率要比 InnoDB 高。

最主要的區別是:MyISAM 表不支援事務、不支援行級鎖、不支援外來鍵。 InnoDB 表支援事務、支援行級鎖、支援外來鍵。(可直接回答這個)

09. 資料庫中 Where、group by、having 關鍵字:

答:  

關鍵字作用:

  1. where 子句用來篩選 from 子句中指定的操作所產生的的行;

  2. group by 子句用來分組 where 子句的輸出;

  3. having 子句用來從分組的結果中篩選行;

having 和 where 的區別:

  1. 語法類似,where 搜尋條件在進行分組操作之前應用;having 搜尋條件在進行分組操作之後應用;

  2. having 可以包含聚合函式 sum、avg、max 等;

  3. having 子句限制的是組,而不是行。

當同時含有 where 子句、group by 子句 、having 子句及聚集函式時,執行順序如下:

  1. 執行 where 子句查詢符合條件的資料;

  2. 使用 group by 子句對資料進行分組;對 group by 子句形成的組執行聚集函式計算每一組的值;最後用 having 子句去掉不符合條件的組。

10. 還有一些問題,如 MySQL 和 SQL Server 用法上的區別、limit 關鍵字的使用等問題。

小結:資料庫方面還是事務機制、隔離級別比較重要,當然了資料庫索引是必考的問題。

偶爾也會給你幾個表,讓你現場寫 SQL 語句,主要考察 group by 和 having 等關鍵字。

 

框架相關知識

 

我在專案中使用的框架有 Spring MVC 和 MyBatis,所以在簡歷上只寫了這兩種框架,面試官主要針對這兩種框架進行提問。以下問題供小夥伴們參考。

JavaWeb 開發經典的 3 層框架:Web 層、Service 層(業務邏輯層)和 Dao 層(資料訪問層)

  • Web 層:包含 JSP 和 Servlet 等與 Web 相關的內容;

  • 業務層:只關心業務邏輯;

  • 資料層:封裝了對資料庫的訪問細節。

Spring 知識點

快速學習 Spring Boot 技術棧

Spring / Spring Boot 原理與實踐

01. Spring 的 IOC 和 AOP 有了解嗎?

答:

  • IOC:控制反轉,(解耦合)將物件間的依賴關係交給 Spring 容器,使用配置檔案來建立所依賴的物件,由主動建立物件改為了被動方式;

  • AOP:面向切面程式設計,將功能程式碼從業務邏輯程式碼中分離出來。

02. AOP 的實現方式有哪幾種?如何選擇?(必考)

答:

JDK 動態代理實現和 cglib 實現。

選擇:

  1. 如果目標物件實現了介面,預設情況下會採用 JDK 的動態代理實現 AOP,也可以強制使用 cglib 實現 AOP;

  2. 如果目標物件沒有實現介面,必須採用 cglib 庫,Spring 會自動在 JDK 動態代理和 cglib 之間轉換。

擴充套件:JDK 動態代理如何實現?(加分點)

答:

JDK 動態代理,只能對實現了介面的類生成代理,而不是針對類,該目標型別實現的介面都將被代理。

原理是通過在執行期間建立一個介面的實現類來完成對目標物件的代理。

  1. 定義一個實現介面 InvocationHandler 的類;

  2. 通過建構函式,注入被代理類;

  3. 實現 invoke( Object proxy, Method method, Object[] args)方法;

  4. 在主函式中獲得被代理類的類載入器;

  5. 使用 Proxy.newProxyInstance( ) 產生一個代理物件;

  6. 通過代理物件呼叫各種方法。

03. Spring MVC 的核心控制器是什麼?訊息處理流程有哪些?

答:

核心控制器為 DispatcherServlet。訊息流程如下:

04. 其他問題包括:重定向和轉發的區別、動態代理和靜態代理的區別等。

Mybatis 知識點

關於 MyBatis 主要考察佔位符#和 $ 的區別,區別如下:

  1. 符號將傳入的資料都當做一個字串,會對自動傳入的資料加一個雙引號;

  2. $ 符號將傳入的資料直接顯示生成 SQL 中;

  3. 符號存在預編譯的過程,,對問號賦值,防止 SQL 注入;

  4. $ 符號是直譯的方式,一般用在 order by ${列名}語句中;

  5. 能用#號就不要用 $ 符號。

小結:限於作者水平,MVC 框架方面瞭解不是太多,實戰能力欠缺。面試官偶爾問框架底層實現原理等都知之甚少,有能力的小夥伴可以多加學習。

 

大資料相關知識

 

大資料相關是因為我的簡歷上寫了 KafKa 相關專案,所以面試官會進行提問 KafKa 相關知識點,我也進行了一些簡單概念總結,深層次的實現原理因為並沒有特別多的實戰經驗,所以並不瞭解。

以下概念總結供小夥伴參考。

01. KafKa 基本特性:

答:

快速持久化、支援批量讀寫訊息、支援訊息分割槽,提高了併發能力、支援線上增加分割槽、支援為每個分割槽建立多個副本。

擴充套件:為什麼可以實現快速持久化?

答:

KafKa 將訊息儲存在磁碟中,並且讀寫磁碟的方式是順序讀寫,避免了隨機讀寫磁碟(尋道時間過長)導致的效能瓶頸;磁碟的順序讀寫速度超過記憶體隨機讀寫。

Kafka 入門與實踐

02. 核心概念

答:

  • 生產者(Producer): 生產訊息,並且按照一定的規則推送到 Topic 的分割槽中。

  • 消費者(Consumer): 從 Topic 中拉去訊息,並且進行消費。

  • 主題(Topic): 用於儲存訊息的邏輯概念,是一個訊息集合。

  • 分割槽(partition):

  1. 每個 Topic 可以劃分為多個分割槽,每個訊息在分割槽中都會有一個唯一編號 offset

  2. kafka 通過 offset 保證訊息在分割槽中的順序

  3. 同一 Topic 的不同分割槽可以分配在不同的 Broker 上

  4. partition 以檔案的形式儲存在檔案系統中。

副本(replica):

  1. KafKa 對訊息進行了冗餘備份,每個分割槽有多個副本,每個副本中包含的訊息是 “一樣” 的。

  2. 每個副本中都會選舉出一個 Leader 副本,其餘為 Follower 副本,Follower 副本僅僅將資料從 Leader 副本拉去到本地,然後同步到自己的 Log 中。

消費者組(Consumer Group): 每個 consumer 都屬於一個 consumer group,每條訊息只能被 consumer group 中的一個 Consumer 消費,但可以被多個 consumer group 消費。

Broker:

  1. 一個單獨的 server 就是一個 Broker;

  2. 主要工作:接收生產者發過來的訊息,分配 offset,並且儲存到磁碟中;

Cluster&Controller:

  1. 多個 Broker 可以組成一個 Cluster,每個叢集選舉一個 Broker 來作為 Controller,充當指揮中心

  2. Controller 負責管理分割槽的狀態,管理每個分割槽的副本狀態,監聽 ZooKeeper 中資料的變化等工作

保留策略和日誌壓縮:

  1. 不管消費者是否已經消費了訊息,KafKa 都會一直儲存這些訊息(持久化到磁碟);

  2. 通過保留策略,定時刪除陳舊的訊息;

  3. 日誌壓縮,只保留最新的 Key-Value 對。

關於副本機制:(加分點)

ISR 集合 :表示當前 “可用” 且訊息量與 Leader 相差不多的副本集合。滿足條件如下:

  1. 副本所在節點必須維持著與 ZooKeeper 的連線;

  2. 副本最後一條資訊的 offset 與 Leader 副本的最後一條訊息的 offset 之間的差值不能超過指定的閾值。

    深入淺出理解基於 Kafka 和 ZooKeeper 的分散式訊息佇列

HW&LEO:

  1. HW 標記了一個特殊的 offset,當消費者處理訊息的時候,只能拉取到 HW 之前的訊息;

  2. HW 也是由 Leader 副本管理的;

  3. LEO(Log End Offset)是所有副本都會有的一個 offset 標記。

ISR、HW 和 LEO 的工作配合:

  1. producer 向此分割槽中推送訊息;

  2. Leader 副本將訊息追加到 Log 中,並且遞增其 LEO;

  3. Follower 副本從 Leader 副本中拉取訊息進行同步;

  4. Follower 副本將訊息更新到本地 Log 中,並且遞增其 LEO;

  5. 當 ISR 集合中的所有副本都完成了對 offset 的訊息同步,Leader 副本會遞增其 HW

KafKa 的容災機制:通過分割槽的副本 Leader 副本和 Follower 副本來提高容災能力。

小結:請小夥伴根據自己的簡歷自行準備學習大資料相關知識點。

 

Linux 常見命令

 

作者對這一方面不是很精通,知識點來源於網路總結以及面試官的提問,僅供小夥伴參考。

01. grep、sed 以及 awk 命令

解析:awk 命令如果可以掌握,是面試中的一個  加分點。

02. 檔案和目錄:

pwd 顯示當前目錄

ls 顯示當前目錄下的檔案和目錄:

  1. ls -F 可以區分檔案和目錄;

  2. ls -a 可以把隱藏檔案和普通檔案一起顯示出來;

  3. ls -R 可以遞迴顯示子目錄中的檔案和目錄;

  4. ls -l 顯示長列表;

  5. ls -l test 過濾器,檢視某個特定檔案資訊。可以只檢視 test 檔案的資訊。

03. 處理檔案方面的命令有:touch、cp、 In、mv、rm、          

04. 處理目錄方面的命令:mkdir

05. 檢視檔案內容:file、cat、more、less、tail、head

06. 監測程式命令:ps、top

eg. 找出程式名中包括 java 的所有程式:ps -ef | grep java

top 命令 實時監測程式

top 命令輸出的第一部分:顯示系統的概括。

  1. 第一行顯示了當前時間、系統的執行時間、登入的使用者數和系統的平均負載(平均負載有 3 個值:最近 1min 5min 15min);

  2. 第二行顯示了程式的概要資訊,有多少程式處於執行、休眠、停止或者僵化狀態;

  3. 第三行是 CPU 的概要資訊;

  4. 第四行是系統記憶體的狀態。

07. ps 和 top 命令的區別:

  1. ps 看到的是命令執行瞬間的程式資訊 , 而 top 可以持續的監視;

  2. ps 只是檢視程式 , 而 top 還可以監視系統效能 , 如平均負載 ,cpu 和記憶體的消耗;

  3. 另外 top 還可以操作程式 , 如改變優先順序 (命令 r) 和關閉程式 (命令 k);

  4. ps 主要是檢視程式的,關注點在於檢視需要檢視的程式;

  5. top 主要看 cpu, 記憶體使用情況,及佔用資源最多的程式由高到低排序,關注點在於資源佔用情況。

08. 壓縮資料

  1. tar -xvf 檔名;

  2. tar -zxvf 檔名;

  3. tar -cvzf 檔名。

09. 結束程式:kill PID 或者 kill all

結束語

至此,從十個不同的方面闡述了 Java 開發面試崗位中所涉及到的重要知識點。

相關文章