最近發現網上很多Java面試題都沒有答案,所以花了很長時間搜集整理出來了這套Java面試題大全,希望大家能夠喜歡!
注:篇幅有限,資料已整理成文檔,后臺si我666,我一個個發!
這套面試文檔包含了:Java基礎、JVM、多線程&并發、spring、mybatis、springboot、MySQL、springcloud、Dubbo、Nginx、MQ、數據結構與算法、Linux、Zookeeper、Redis篇、分布式、網絡篇、設計模式、maven篇、ElasticSearch篇、tomcat篇、Git篇、軟實力篇,應有盡有、一網打盡!
一、基礎篇
1、 Java語言有哪些特點?
簡單易學、有豐富的類庫
面向對象(Java最重要的特性,讓程序耦合度更低,內聚性更高)
與平臺無關性(JVM是Java跨平臺使用的根本)
可靠安全
支持多線程
2、面向對象和面向過程的區別
面向過程:是分析解決問題的步驟,然后用函數把這些步驟一步一步地實現,然后在使用的時候一 一調用則可。性能較高,所以單片機、嵌入式開發等一般采用面向過程開發
面向對象:是把構成問題的事務分解成各個對象,而建立對象的目的也不是為了完成一個個步驟, 而是為了描述某個事物在解決整個問題的過程中所發生的行為。面向對象有封裝、繼承、多態的特 性,所以易維護、易復用、易擴展。可以設計出低耦合的系統。 但是性能上來說,比面向過程要 低。
3 、八種基本數據類型的大小,以及他們的封裝類
注:
1.int是基本數據類型,Integer是int的封裝類,是引用類型。int默認值是0,而Integer默認值是null,所以Integer能區分出0和null的情況。一旦java看到null,就知道這個引用還沒有指向某個對象,再任何引用使用前,必須為其指定一個對象,否則會報錯。
2.基本數據類型在聲明時系統會自動給它分配空間,而引用類型聲明時只是分配了引用空間,必須通過實例化開辟數據空間之后才可以賦值。數組對象也是一個引用對象,將一個數組賦值給另一個數組時只是復制了一個引用,所以通過某一個數組所做的修改在另一個數組中也看的見。
雖然定義了boolean這種數據類型,但是只對它提供了非常有限的支持。在Java虛擬機中沒有任何供boolean值專用的字節碼指令,Java語言表達式所操作的boolean值,在編譯之后都使用Java虛擬機中的int數據類型來代替,而boolean數組將會被編碼成Java虛擬機的byte數組,每個元素 boolean元素占8位。這樣我們可以得出boolean類型占了單獨使用是4個字節,在數組中又是1個字 節。使用int的原因是,對于當下32位的處理器(CPU)來說,一次處理數據是32位(這里不是指的是32/64位系統,而是指CPU硬件層面),具有高效存取的特點。
4、標識符的命名規則。
標識符的含義: 是指在程序中,我們自己定義的內容,譬如,類的名字,方法名稱以及變量名稱等等,都是標識符。
命名規則:(硬性要求) 標識符可以包含英文字母,0-9的數字,$以及_ 標識符不能以數字開頭 標識符不是關鍵字
命名規范:(非硬性要求) 類名規范:首字符大寫,后面每個單詞首字母大寫(大駝峰式)。 變量名規范:首字母小寫,后面每個單詞首字母大寫(小駝峰式)。 方法名規范:同變量名。
5、instanceof 關鍵字的作用
instanceof 嚴格來說是Java中的一個雙目運算符,用來測試一個對象是否為一個類的實例,用法 為:
boolean result = obj instanceof Class
其中 obj 為一個對象,Class 表示一個類或者一個接口,當 obj 為 Class 的對象,或者是其直接或間接子類,或者是其接口的實現類,結果result 都返回 true,否則返回false。
注意:編譯器會檢查 obj 是否能轉換成右邊的class類型,如果不能轉換則直接報錯,如果不能確定類型,則通過編譯,具體看運行時定。
int i = 0;
System.out.println(i instanceof Integer);//編譯不通過 i必須是引用類型,不能是基本類型
System.out.println(i instanceof Object);//編譯不通過
Integer integer = new Integer(1);
System.out.println(integer instanceof Integer);//true
//false ,在 JavaSE規范 中對 instanceof 運算符的規定就是:如果 obj 為 null,那么將返回 false。
System.out.println(null instanceof Object);
6、Java自動裝箱與拆箱
裝箱就是自動將基本數據類型轉換為包裝器類型(int-->Integer);調用方法:Integer的valueOf(int) 方法
拆箱就是自動將包裝器類型轉換為基本數據類型(Integer-->int)。調用方法:Integer的 intValue方法
在Java SE5之前,如果要生成一個數值為10的Integer對象,必須這樣進行:
Integer i = new Integer(10);
而在從 Java SE5 開始就提供了自動裝箱的特性,如果要生成一個數值為 10 的 Integer 對象,只需要這樣就可以了:
Integer i = 10;
面試題 1 : 以下代碼會輸出什么?
為什么會出現這樣的結果?輸出結果表明 i1 和 i2 指向的是同一個對象,而 i3 和 i4 指向的是不同的對
象。此時只需一看源碼便知究竟,下面這段代碼是 Integer 的 valueOf 方法的具體實現:
其中 IntegerCache 類的實現為:
從這2段代碼可以看出,在通過valueOf方法創建Integer對象的時候,如果數值在[-128,127]之間, 便返回指向IntegerCache.cache中已經存在的對象的引用;否則創建一個新的Integer對象。
上面的代碼中i1和i2的數值為100,因此會直接從cache中取已經存在的對象,所以i1和i2指向的是同一個對象,而i3和i4則是分別指向不同的對象。
面試題2:以下代碼輸出什么
7、 重載和重寫的區別
重寫(Override)
從字面上看,重寫就是 重新寫一遍的意思。其實就是在子類中把父類本身有的方法重新寫一遍。子類繼承了父類原有的方法,但有時子類并不想原封不動的繼承父類中的某個方法,所以在方法名,參數列表,返回類型(除過子類中方法的返回值是父類中方法返回值的子類時)都相同的情況下, 對方法體進行修改或重寫,這就是重寫。但要注意子類函數的訪問修飾權限不能少于父類的。
重寫 總結: 1.發生在父類與子類之間 2.方法名,參數列表,返回類型(除過子類中方法的返回類型是父類中返回類型的子類)必須相同 3.訪問修飾符的限制一定要大于被重寫方法的訪問修飾符 (public>protected>default>private)
4.重寫方法一定不能拋出新的檢查異常或者比被重寫方法申 明更加寬泛的檢查型異常
重載(Overload)
在一個類中,同名的方法如果有不同的參數列表(參數類型不同、參數個數不同甚至是參數順序不 同)則視為重載。同時,重載對返回類型沒有要求,可以相同也可以不同,但不能通過返回類型是 否相同來判斷重載。
重載 總結: 1.重載Overload是一個類中多態性的一種表現 2.重載要求同名方法的參數列表不同(參 數類型,參數個數甚至是參數順序) 3.重載的時候,返回值類型可以相同也可以不相同。無法以返回型別作為重載函數的區分標準
篇幅限制下面就只能給大家展示小冊部分內容了。這份面試筆記包括了:Java基礎、JVM、多線程&并發、spring、mybatis、springboot、MySQL、springcloud、Dubbo、Nginx、MQ、數據結構與算法、Linux、Zookeeper、Redis篇、分布式、網絡篇、設計模式、maven篇、ElasticSearch篇、tomcat篇、Git篇、軟實力篇 面試專題
需要全套面試筆記的【 查看文章末尾名片】即可免費獲取
二、JVM篇
1、知識點匯總
JVM是Java運行基礎,面試時一定會遇到JVM的有關問題,內容相對集中,但對只是深度要求較高.
其中內存模型,類加載機制,GC是重點方面.性能調優部分更偏向應用,重點突出實踐能力.編譯器優化 和執行模式部分偏向于理論基礎,重點掌握知識點.
需了解 內存模型各部分作用,保存哪些數據.
類加載雙親委派加載機制,常用加載器分別加載哪種類型的類.
GC分代回收的思想和依據以及不同垃圾回收算法的回收思路和適合場景.
性能調優常有JVM優化參數作用,參數調優的依據,常用的JVM分析工具能分析哪些問題以及使用方法.
執行模式解釋/編譯/混合模式的優缺點,Java7提供的分層編譯技術,JIT即時編譯技術,OSR棧上替換,C1/C2編譯器針對的場景,C2針對的是server模式,優化更激進.新技術方面Java10的graal編譯器
編譯器優化javac的編譯過程,ast抽象語法樹,編譯器優化和運行器優化.
2、知識點詳解:
1)、JVM內存模型:
線程獨占:棧,本地方法棧,程序計數器 線程共享:堆,方法區
2)、棧:
又稱方法棧,線程私有的,線程執行方法是都會創建一個棧陣,用來存儲局部變量表,操作棧,動態鏈接,方法出口等信息.調用方法時執行入棧,方法返回式執行出棧.
3)、本地方法棧
與棧類似,也是用來保存執行方法的信息.執行Java方法是使用棧,執行Native方法時使用本地方法棧.
4)、程序計數器
保存著當前線程執行的字節碼位置,每個線程工作時都有獨立的計數器,只為執行Java方法服務,執行 Native方法時,程序計數器為空.
5)、堆
JVM內存管理最大的一塊,對被線程共享,目的是存放對象的實例,幾乎所欲的對象實例都會放在這里, 當堆沒有可用空間時,會拋出OOM異常.根據對象的存活周期不同,JVM把對象進行分代管理,由垃圾回收器進行垃圾的回收管理
6)、方法區:
又稱非堆區,用于存儲已被虛擬機加載的類信息,常量,靜態變量,即時編譯器優化后的代碼等數據.1.7 的永久代和1.8的元空間都是方法區的一種實現
7)、JVM 內存可見性
JMM 是定義程序中變量的訪問規則 , 線程對于變量的操作只能在自己的工作內存中進行 , 而不能直接對主內存操作. 由于指令重排序 , 讀寫的順序會被打亂 , 因此 JMM 需要提供原子性 , 可見性 , 有序性保證 .
3、說說類加載與卸載
加載過程
其中驗證,準備,解析合稱鏈接
加載通過類的完全限定名,查找此類字節碼文件,利用字節碼文件創建Class對象.
驗證確保Class文件符合當前虛擬機的要求,不會危害到虛擬機自身安全.
準備進行內存分配,為static修飾的類變量分配內存,并設置初始值(0或null).不包含final修飾的靜態變 量,因為final變量在編譯時分配.
解析將常量池中的符號引用替換為直接引用的過程.直接引用為直接指向目標的指針或者相對偏移量等.
初始化主要完成靜態塊執行以及靜態變量的賦值.先初始化父類,再初始化當前類.只有對類主動使用 時才會初始化.
觸發條件包括,創建類的實例時,訪問類的靜態方法或靜態變量的時候,使用Class.forName反射類的時候,或者某個子類初始化的時候.
Java自帶的加載器加載的類,在虛擬機的生命周期中是不會被卸載的,只有用戶自定義的加載器加載的類才可以被卸.
1)、加載機制-雙親委派模式
雙親委派模式,即加載器加載類時先把請求委托給自己的父類加載器執行,直到頂層的啟動類加載器. 父類加載器能夠完成加載則成功返回,不能則子類加載器才自己嘗試加載.*
優點:
1. 避免類的重復加載
2. 避免Java的核心API被篡改
2)、分代回收
分代回收基于兩個事實:大部分對象很快就不使用了,還有一部分不會立即無用,但也不會持續很長時 間.
年輕代->標記-復制 老年代->標記-清除
3、回收算法
a、G1算法
1.9后默認的垃圾回收算法,特點保持高回收率的同時減少停頓.采用每次只清理一部分,而不是清理全部的增量式清理,以保證停頓時間不會過長
其取消了年輕代與老年代的物理劃分,但仍屬于分代收集器,算法將堆分為若干個邏輯區域(region),一部分用作年輕代,一部分用作老年代,還有用來存儲巨型對象的分區.
同CMS相同,會遍歷所有對象,標記引用情況,清除對象后會對區域進行復制移動,以整合碎片空間.
年輕代回收: 并行復制采用復制算法,并行收集,會StopTheWorld.
老年代回收: 會對年輕代一并回收
初始標記完成堆root對象的標記,會StopTheWorld. 并發標記 GC線程和應用線程并發執行. 最終標記完成三色標記周期,會StopTheWorld. 復制/清楚會優先對可回收空間加大的區域進行回收
b、ZGC算法
前面提供的高效垃圾回收算法,針對大堆內存設計,可以處理TB級別的堆,可以做到10ms以下的回收停頓時間.
著色指針
讀屏障
并發處理
基于region
內存壓縮(整理)
roots標記:標記root對象,會StopTheWorld. 并發標記:利用讀屏障與應用線程一起運行標記,可能 會發生StopTheWorld. 清除會清理標記為不可用的對象. roots重定位:是對存活的對象進行移動,以騰出大塊內存空間,減少碎片產生.重定位最開始會StopTheWorld,卻決于重定位集與對象總活動集的比例. 并發重定位與并發標記類似.
4、簡述一下JVM的內存模型
1).JVM內存模型簡介
JVM定義了不同運行時數據區,他們是用來執行應用程序的。某些區域隨著JVM啟動及銷毀,另外一些區域的數據是線程性獨立的,隨著線程創建和銷毀。jvm內存模型總體架構圖如下:(摘自oracle官方網站)
JVM在執行Java程序時,會把它管理的內存劃分為若干個的區域,每個區域都有自己的用途和創建 銷毀時間。如下圖所示,可以分為兩大部分,線程私有區和共享區。下圖是根據自己理解畫的一個 JVM內存模型架構圖:
JVM內存分為線程私有區和線程共享區
線程私有區
1)、程序計數器
當同時進行的線程數超過CPU數或其內核數時,就要通過時間片輪詢分派CPU的時間資源,不免發生線程切換。這時,每個線程就需要一個屬于自己的計數器來記錄下一條要運行的指令。如果執行的是JAVA方法,計數器記錄正在執行的java字節碼地址,如果執行的是native方法,則計數器為 空。
2)、虛擬機棧
線程私有的,與線程在同一時間創建。管理JAVA方法執行的內存模型。每個方法執行時都會創建一個楨棧來存儲方法的的變量表、操作數棧、動態鏈接方法、返回值、返回地址等信息。棧的大小決定了方法調用的可達深度(遞歸多少層次,或嵌套調用多少層其他方法,-Xss參數可以設置虛擬機棧大小)。棧的大小可以是固定的,或者是動態擴展的。如果請求的棧深度大于最大可用深度,則拋出stackOverflowError;如果棧是可動態擴展的,但沒有內存空間支持擴展,則拋出 OutofMemoryError。 使用jclasslib工具可以查看class類文件的結構。下圖為棧幀結構圖:
3)、本地方法棧
與虛擬機棧作用相似。但它不是為Java方法服務的,而是本地方法(C語言)。由于規范對這塊沒有強制要求,不同虛擬機實現方法不同。
線程共享區
1)、方法區
線程共享的,用于存放被虛擬機加載的類的元數據信息,如常量、靜態變量和即時編譯器編譯后的 代碼。若要分代,算是永久代(老年代),以前類大多“static”的,很少被卸載或收集,現回收廢棄 常量和無用的類。其中運行時常量池存放編譯生成的各種常量。(如果hotspot虛擬機確定一個類 的定義信息不會被使用,也會將其回收。回收的基本條件至少有:所有該類的實例被回收,而且裝 載該類的ClassLoader被回收)
2)、堆
存放對象實例和數組,是垃圾回收的主要區域,分為新生代和老年代。剛創建的對象在新生代的 Eden區中,經過GC后進入新生代的S0區中,再經過GC進入新生代的S1區中,15次GC后仍存在就進入老年代。這是按照一種回收機制進行劃分的,不是固定的。若堆的空間不夠實例分配,則 OutOfMemoryError。
Java面試題目錄
多線程&并發篇(46道面試題)
注:篇幅有限,資料已整理成文檔,后臺si我666,我一個個發!