天天看點

萬字長文,62道Java核心面試題,一次性打包送給積極向上的你(1)

二哥,你好,找工作找了仨月,還沒有找到,很焦慮,我該怎麼辦呢?你那有沒有 Java 方面的面試題可以分享一波啊?

以上是讀者田田給我發的私信,看完後于我心有戚戚焉啊,最近境況确實不容樂觀,并非是個人的原因造成的。那,既然需要面試題,二哥就義不容辭,必須得準備一波。

這次我花了一周的時間,準備了 31 道 Java 核心面試題,希望能夠幫助到田田,以及其他和田田類似情況的讀者朋友。

(後續我打算再花一周時間,更新第二波,同樣有 31 道,敬請期待)

01、請說出 Java 14 版本中更新的重要功能

Java 14 釋出于 2020 年 3 月 17 日,更新的重要功能有:

switch 表達式

instanceof 增強表達式,預覽功能

文本塊,第二次預覽

Records,預覽功能

剛好我之前寫過一篇文章,關于 Java 14 的開箱體驗,很香,讀者朋友需要的話,可以點下面的連結看一看。

Java 14 開箱,它真香香香香

02、請說出 Java 13 版本中更新的重要功能

Java 13 釋出于 2019 年 9 月 17 日,更新的重要功能有:

文本塊,預覽功能

switch 表達式,預覽功能

Java Socket 重新實作

FileSystems.newFileSystem() 方法

支援 Unicode 12.1

可伸縮、低延遲的垃圾收集器改進,用于傳回未使用的記憶體

03、請說出 Java 12 版本中更新的重要功能

Java 12 釋出于 2019 年 3 月 19 日,更新的重要功能有:

JVM 更新

File.mismatch() 方法

緊湊型數字格式

String 類新增了一些方法,比如說 indent()

04、請說出 Java 11 版本中更新的重要功能

Java 11 是繼 Java 8 之後的第二個商用版本,如果你下載下傳的是 Oracle JDK,則需要進行付費;如果想繼續使用免費版本,需要下載下傳 Open JDK。

萬字長文,62道Java核心面試題,一次性打包送給積極向上的你(1)

Oracle JDK 中會有一些 Open JDK 沒有的、商用閉源的功能。

Java 11 更新的重要功能有:

可以直接使用 java 指令運作 Java 程式,源代碼将會隐式編譯和運作。

String 類新增了一些方法,比如說 isBlank()、lines()、strip() 等等。

Files 類新增了兩個讀寫方法,readString() 和 writeString()。

可以在 Lambda 表達式中使用 var 作為變量類型。

05、請說出 Java 10 版本中更新的重要功能

Java 10 更新的重要功能有:

局部變量類型推斷,舉個例子,var list = new ArrayList<String>();,可以使用 var 來作為變量類型,Java 編譯器知道 list 的類型為字元串的 ArrayList。

增強 java.util.Locale。

提供了一組預設的根證書頒發機構(CA)。

06、請說出 Java 9 版本中更新的重要功能

Java 9 更新的重要功能有:

子產品系統

不可變的 List、Set、Map 的工廠方法

接口中可以有私有方法

垃圾收集器改進

07、請說出 Java 8 版本中更新的重要功能

Java 8 釋出于 2014 年 3 月份,可以說是 Java 6 之後最重要的版本更新,深受開發者的喜愛。

函數式程式設計和 Lambda 表達式

Stream 流

Java Date Time API

接口中可以使用預設方法和靜态方法

我強烈建議點開上面的連結閱讀以下,以正确了解這些概念。

08、請說出 Java 面向對象程式設計中的一些重要概念

抽象

封裝

多态

繼承

09、Java 聲稱的平台獨立性指的是什麼?

常見的作業系統有 Windows、Linux、OS-X,那麼平台獨立性意味着我們可以在任何作業系統中運作相同源代碼的 Java 程式,比如說我們可以在 Windows 上編寫 Java 程式,然後在 Linux 上運作它。

10、什麼是 JVM?

JVM(Java Virtual Machine)俗稱 Java 虛拟機。之是以稱為虛拟機,是因為它實際上并不存在。它提供了一種運作環境,可供 Java 位元組碼在上面運作。

JVM 提供了以下操作:

加載位元組碼

驗證位元組碼

執行位元組碼

提供運作時環境

JVM 定義了以下内容:

存儲區

類檔案格式

寄存器組

垃圾回收堆

緻命錯誤報告等

我們來嘗試了解一下 JVM 的内部結構,它包含了類加載器(Class Loader)、運作時資料區(Runtime Data Areas)和執行引擎(Excution Engine)。

萬字長文,62道Java核心面試題,一次性打包送給積極向上的你(1)

1)類加載器

類加載器是 JVM 的一個子系統,用于加載類檔案。每當我們運作一個 Java 程式,它都會由類加載器首先加載。Java 中有三個内置的類加載器:

啟動類加載器(Bootstrap Class-Loader),加載 jre/lib 包下面的 jar 檔案,比如說常見的 rt.jar(包含了 Java 标準庫下的所有類檔案,比如說 java.lang 包下的類,java.net 包下的類,java.util 包下的類,java.io 包下的類,java.sql 包下的類)。

擴充類加載器(Extension or Ext Class-Loader),加載 jre/lib/ext 包下面的 jar 檔案。

應用類加載器(Application or App Clas-Loader),根據程式的類路徑(classpath)來加載 Java 類。

一般來說,Java 程式員并不需要直接同類加載器進行互動。JVM 預設的行為就已經足夠滿足大多數情況的需求了。不過,如果遇到了需要和類加載器進行互動的情況,而對類加載器的機制又不是很了解的話,就不得不花大量的時間去調試

ClassNotFoundException 和 NoClassDefFoundError 等異常。

對于任意一個類,都需要由它的類加載器和這個類本身一同确定其在 JVM 中的唯一性。也就是說,如果兩個類的加載器不同,即使兩個類來源于同一個位元組碼檔案,那這兩個類就必定不相等(比如兩個類的 Class 對象不 equals)。

是不是有點暈,來來來,通過一段簡單的代碼了解下。

public class Test {
    public static void main(String[] args) {
  ClassLoader loader = Test.class.getClassLoader();
  while (loader != null) {
    System.out.println(loader.toString());
    loader = loader.getParent();
  }
    }
}      

每個 Java 類都維護着一個指向定義它的類加載器的引用,通過 類名.class.getClassLoader() 可以擷取到此引用;然後通過 loader.getParent() 可以擷取類加載器的上層類加載器。

上面這段代碼的輸出結果如下:

sun.misc.Launcher$AppClassLoader@18b4aac2

sun.misc.Launcher$ExtClassLoader@4617c264

第一行輸出為 Test 的類加載器,即應用類加載器,它是 sun.misc.Launcher$AppClassLoader 類的執行個體;第二行輸出為擴充類加載器,是 sun.misc.Launcher$ExtClassLoader 類的執行個體。那啟動類加載器呢?

按理說,擴充類加載器的上層類加載器是啟動類加載器,但在我這個版本的 JDK 中, 擴充類加載器的 getParent() 傳回 null。是以沒有輸出。

2)運作時資料區

運作時資料區又包含以下内容。

萬字長文,62道Java核心面試題,一次性打包送給積極向上的你(1)

PC寄存器(PC Register),也叫程式計數器(Program Counter Register),是一塊較小的記憶體空間,它的作用可以看做是目前線程所執行的位元組碼的信号訓示器。

JVM 棧(Java Virtual Machine Stack),與 PC 寄存器一樣,JVM 棧也是線程私有的。每一個 JVM 線程都有自己的 JVM 棧,這個棧與線程同時建立,它的生命周期與線程相同。

本地方法棧(Native Method Stack),JVM 可能會使用到傳統的棧來支援 Native 方法(使用 Java 語言以外的其它語言[C語言]編寫的方法)的執行,這個棧就是本地方法棧。

堆(Heap),在 JVM 中,堆是可供各條線程共享的運作時記憶體區域,也是供所有類執行個體和資料對象配置設定記憶體的區域。

方法區(Method area),在 JVM 中,被加載類型的資訊都儲存在方法區中。包括類型資訊(Type Information)和方法清單(Method Tables)。方法區是所有線程共享的,是以通路方法區資訊的方法必須是線程安全的。

運作時常量池(Runtime Constant Pool),運作時常量池是每一個類或接口的常量池在運作時的表現形式,它包括了編譯器可知的數值字面量,以及運作期解析後才能獲得的方法或字段的引用。簡而言之,當一個方法或者變量被引用時,JVM 通過運作時常量區來查找方法或者變量在記憶體裡的實際位址。

3)執行引擎

執行引擎包含了:

解釋器:讀取位元組碼流,然後執行指令。因為它一條一條地解釋和執行指令,是以它可以很快地解釋位元組碼,但是執行起來會比較慢。

即時(Just-In-Time,JIT)編譯器:即時編譯器用來彌補解釋器的缺點,提高性能。執行引擎首先按照解釋執行的方式來執行,然後在合适的時候,即時編譯器把整段位元組碼編譯成本地代碼。然後,執行引擎就沒有必要再去解釋執行方法了,它可以直接通過本地代碼去執行。執行本地代碼比一條一條進行解釋執行的速度快很多。編譯後的代碼可以執行的很快,因為本地代碼是儲存在緩存裡的。