本文收錄于《面試小抄》系列,Github地址:https://github.com/cosen1024/Java-Interview
這是一個很干的面試題合集,主要涉及Java基礎、Java并發、JVM、MySQL、Redis、Spring、MyBatis、Kafka、作業系統、計算機網路等知識點,
Java基礎內容較多,我將分成兩篇,這是本期的 Java 基礎面試題目錄,看看你會哪些?

話不多說,開始發車了~
1. Java語言有哪些特點?
- 面向物件(封裝,繼承,多型);
- 平臺無關性,平臺無關性的具體表現在于,Java 是“一次撰寫,到處運行(Write Once,Run any Where)”的語言,因此采用 Java 語言撰寫的程式具有很好的可移植性,而保證這一點的正是 Java 的虛擬機機制,在引入虛擬機之后,Java 語言在不同的平臺上運行不需要重新編譯,
- 可靠性、安全性;
- 支持多執行緒,C++ 語言沒有內置的多執行緒機制,因此必須呼叫作業系統的多執行緒功能來進行多執行緒程式設計,而 Java 語言卻提供了多執行緒支持;
- 支持網路編程并且很方便,Java 語言誕生本身就是為簡化網路編程設計的,因此 Java 語言不僅支持網路編程而且很方便;
- 編譯與解釋并存;
2. Java和C++有什么關系,它們有什么區別?
- 都是面向物件的語言,都支持封裝、繼承和多型;
- C++ 支持指標,而 Java 沒有指標的概念;
- C++ 支持多繼承,而 Java 不支持多重繼承,但允許一個類實作多個介面;
- Java 自動進行無用記憶體回收操作,不再需要程式員進行手動洗掉,而 C++ 中必須由程式釋放記憶體資源,這就增加了程式員的負擔,
- Java 不支持運算子多載,運算子多載則被認為是 C++ 的突出特征;
- Java 是完全面向物件的語言,并且還取消了 C/C++ 中的結構和聯合,使編譯程式更加簡潔;
- C 和 C++ 不支持字串變數,在 C 和 C++ 程式中使用“Null”終止符代表字串的結束,在 Java 中字串是用類物件(String 和 StringBuffer)來實作的;
- goto 陳述句是 C 和 C++ 的“遺物”,Java 不提供 goto 陳述句,雖然 Java 指定 goto 作為關鍵字,但不支持它的使用,這使程式更簡潔易讀;
3. JVM、JRE和JDK的關系是什么?
JDK是(Java Development Kit)的縮寫,它是功能齊全的 Java SDK,它擁有 JRE 所擁有的一切,還有編譯器(javac)和工具(如 javadoc 和 jdb),它能夠創建和編譯程式,
JRE是Java Runtime Environment縮寫,它是運行已編譯 Java 程式所需的所有內容的集合,包括 Java 虛擬機(JVM),Java 類別庫,java 命令和其他的一些基礎構件,但是,它不能用于創建新程式,
JDK包含JRE,JRE包含JVM,

4. 什么是位元組碼?采用位元組碼的好處是什么?
這個問題,面試官可以擴展提問,Java 是編譯執行的語言,還是解釋執行的語言?
Java之所以可以“一次編譯,到處運行”,一是因為JVM針對各種作業系統、平臺都進行了定制,二是因為無論在什么平臺,都可以編譯生成固定格式的位元組碼(.class檔案)供JVM使用,因此,也可以看出位元組碼對于Java生態的重要性,
之所以被稱之為位元組碼,是因為位元組碼檔案由十六進制值組成,而JVM以兩個十六進制值為一組,即以位元組為單位進行讀取,在Java中一般是用javac命令編譯源代碼為位元組碼檔案,一個.java檔案從編譯到運行的示例如圖所示,

Java語言通過位元組碼的方式,在一定程度上解決了傳統解釋型語言執行效率低的問題,同時又保留了解釋型語言可移植的特點,所以Java程式運行時比較高效,而且,由于位元組碼并不專對一種特定的機器,因此,Java程式無須重新編譯便可在多種不同的計算機上運行,
5. Oracle JDK 和 OpenJDK 的區別是什么?
可能在看這個問題之前很多人和我一樣并沒有接觸和使用過 OpenJDK ,下面通過我通過我收集到一些資料對你解答這個被很多人忽視的問題,
- Oracle JDK 版本將每三年發布一次,而 OpenJDK 版本每三個月發布一次;
- OpenJDK 是一個參考模型并且是完全開源的,而 Oracle JDK 是OpenJDK 的一個實作,并不是完全開源的;
- Oracle JDK 比 OpenJDK 更穩定,OpenJDK 和 Oracle JDK 的代碼幾乎相同,但 Oracle JDK 有更多的類和一些錯誤修復,因此,如果您想開發企業/商業軟體,建議選擇 Oracle JDK,因為它經過了徹底的測驗和穩定,某些情況下,有些人提到在使用 OpenJDK 可能會遇到了許多應用程式崩潰的問題,但是,只需切換到 Oracle JDK 就可以解決問題;
- 在回應性和 JVM 性能方面,Oracle JDK 與 OpenJDK 相比提供了更好的性能;
- Oracle JDK 不會為即將發布的版本提供長期支持,用戶每次都必須通過更新到最新版本獲得支持來獲取最新版本;
- Oracle JDK 根據二進制代碼許可協議獲得許可,而 OpenJDK 根據 GPLv2 許可獲得許可,
6. Java有哪些資料型別?
Java 語言的資料型別分為兩種:基本資料型別和參考資料型別,

基本資料型別包括 boolean(布爾型)、float(單精度浮點型)、char(字符型)、byte(位元組型)、short(短整型)、int(整型)、long(長整型)和 double (雙精度浮點型)共 8 種,如下圖所示,
image-
參考資料型別建立在基本資料型別的基礎上,包括陣列、類和介面,參考資料型別是由用戶自定義,用來限制其他資料的型別,另外,Java 語言中不支持 C++ 中的指標型別、結構型別、聯合型別和列舉型別,
7. switch 是否能作用在 byte 上,是否能作用在 long 上,是否能作用在 String 上?
Java5 以前 switch(expr)中,expr 只能是 byte、short、char、int,
從 Java 5 開始,Java 中引入了列舉型別, expr 也可以是 enum 型別,
從 Java 7 開始,expr還可以是字串(String),但是長整型(long)在目前所有的版本中都是不可以的,
8. 訪問修飾符public、private、protected、以及不寫(默認)時的區別?
Java中,可以使用訪問控制符來保護對類、變數、方法和構造方法的訪問,Java 支持 4 種不同的訪問權限,
- default (即默認,什么也不寫): 在同一包內可見,不使用任何修飾符,使用物件:類、介面、變數、方法,
- private : 在同一類內可見,使用物件:變數、方法,注意:不能修飾類(外部類)
- public : 對所有類可見,使用物件:類、介面、變數、方法
- protected : 對同一包內的類和所有子類可見,使用物件:變數、方法,注意:不能修飾類(外部類),

9. break ,continue ,return 的區別及作用?
- break 跳出總上一層回圈,不再執行回圈(結束當前的回圈體)
- continue 跳出本次回圈,繼續執行下次回圈(結束正在執行的回圈 進入下一個回圈條件)
- return 程式回傳,不再執行下面的代碼(結束當前的方法 直接回傳)
10. final、finally、finalize的區別?
final 用于修飾變數、方法和類,
- final 變數:被修飾的變數不可變,不可變分為
參考不可變和物件不可變,final 指的是參考不可變,final 修飾的變數必須初始化,通常稱被修飾的變數為常量, - final 方法:被修飾的方法不允許任何子類重寫,子類可以使用該方法,
- final 類:被修飾的類不能被繼承,所有方法不能被重寫,
finally 作為例外處理的一部分,它只能在 try/catch 陳述句中,并且附帶一個陳述句塊表示這段陳述句最終一定被執行(無論是否拋出例外),經常被用在需要釋放資源的情況下,System.exit (0) 可以阻斷 finally 執行,
finalize 是在 java.lang.Object 里定義的方法,也就是說每一個物件都有這么個方法,這個方法在 gc 啟動,該物件被回收的時候被呼叫,
一個物件的 finalize 方法只會被呼叫一次,finalize 被呼叫不一定會立即回收該物件,所以有可能呼叫 finalize 后,該物件又不需要被回收了,然后到了真正要被回收的時候,因為前面呼叫過一次,所以不會再次呼叫 finalize 了,進而產生問題,因此不推薦使用 finalize 方法,
11. 為什么要用static關鍵字?
通常來說,用new創建類的物件時,資料存盤空間才被分配,方法才供外界呼叫,但有時我們只想為特定域分配單一存盤空間,不考慮要創建多少物件或者說根本就不創建任何物件,再就是我們想在沒有創建物件的情況下也想呼叫方法,在這兩種情況下,static關鍵字,滿足了我們的需求,
12. ”static”關鍵字是什么意思?Java中是否可以覆寫(override)一個private或者是static的方法?
“static”關鍵字表明一個成員變數或者是成員方法可以在沒有所屬的類的實體變數的情況下被訪問,
Java中static方法不能被覆寫,因為方法覆寫是基于運行時動態系結的,而static方法是編譯時靜態系結的,static方法跟類的任何實體都不相關,所以概念上不適用,
13. 是否可以在static環境中訪問非static變數?
static變數在Java中是屬于類的,它在所有的實體中的值是一樣的,當類被Java虛擬機載入的時候,會對static變數進行初始化,如果你的代碼嘗試不用實體來訪問非static的變數,編譯器會報錯,因為這些變數還沒有被創建出來,還沒有跟任何實體關聯上,
14. static靜態方法能不能參考非靜態資源?
不能,new的時候才會產生的東西,對于初始化后就存在的靜態資源來說,根本不認識它,
15. static靜態方法里面能不能參考靜態資源?
可以,因為都是類初始化的時候加載的,大家相互都認識,
16. 非靜態方法里面能不能參考靜態資源?
可以,非靜態方法就是實體方法,那是new之后才產生的,那么屬于類的內容它都認識,
17. java靜態變數、代碼塊、和靜態方法的執行順序是什么?
基本上代碼塊分為三種:Static靜態代碼塊、構造代碼塊、普通代碼塊
代碼塊執行順序靜態代碼塊——> 構造代碼塊 ——> 建構式——> 普通代碼塊
繼承中代碼塊執行順序:父類靜態塊——>子類靜態塊——>父類代碼塊——>父類構造器——>子類代碼塊——>子類構造器
想要深入了解,可以參考這篇文章 :https://juejin.cn/post/6844903986475040781
18. 面向物件和面向程序的區別?
面向程序:
- 優點:性能比面向物件高,因為類呼叫時需要實體化,開銷比較大,比較消耗資源;比如單片機、嵌入式開發、Linux/Unix等一般采用面向程序開發,性能是最重要的因素,
- 缺點:沒有面向物件易維護、易復用、易擴展,
面向物件:
- 優點:易維護、易復用、易擴展,由于面向物件有封裝、繼承、多型性的特性,可以設計出低耦合的系統,使系統更加靈活、更加易于維護,
- 缺點:性能比面向程序低,
19. 講講面向物件三大特性
- 封裝,封裝最好理解了,封裝是面向物件的特征之一,是物件和類概念的主要特性,封裝,也就是把客觀事物封裝成抽象的類,并且類可以把自己的資料和方法只讓可信的類或者物件操作,對不可信的進行資訊隱藏,
- 繼承,繼承是指這樣一種能力:它可以使用現有類的所有功能,并在無需重新撰寫原來的類的情況下對這些功能進行擴展,通過繼承創建的新類稱為“子類”或“派生類”,被繼承的類稱為“基類”、“父類”或“超類”,
- 多型性,它是指在父類中定義的屬性和方法被子類繼承之后,可以具有不同的資料型別或表現出不同的行為,這使得同一個屬性或方法在父類及其各個子類中具有不同的含義,
20. Java語言是如何實作多型的?
本質上多型分兩種:
1、編譯時多型(又稱靜態多型)
2、運行時多型(又稱動態多型)
多載(overload)就是編譯時多型的一個例子,編譯時多型在編譯時就已經確定,運行的時候呼叫的是確定的方法,
我們通常所說的多型指的都是運行時多型,也就是編譯時不確定究竟呼叫哪個具體方法,一直延遲到運行時才能確定,這也是為什么有時候多型方法又被稱為延遲方法的原因,
Java實作多型有 3 個必要條件:繼承、重寫和向上轉型,只有滿足這 3 個條件,開發人員才能夠在同一個繼承結構中使用統一的邏輯實作代碼處理不同的物件,從而執行不同的行為,
- 繼承:在多型中必須存在有繼承關系的子類和父類,
- 重寫:子類對父類中某些方法進行重新定義,在呼叫這些方法時就會呼叫子類的方法,
- 向上轉型:在多型中需要將子類的參考賦給父類物件,只有這樣該參考才既能可以呼叫父類的方法,又能呼叫子類的方法,
Java多型的實作原理可看這篇文章:https://my.oschina.net/u/4432600/blog/4535042
21. 多載(Overload)和重寫(Override)的區別是什么?
方法的多載和重寫都是實作多型的方式,區別在于前者實作的是編譯時的多型性,而后者實作的是運行時的多型性,
- 重寫發生在子類與父類之間, 重寫方法回傳值和形參都不能改變,與方法回傳值和訪問修飾符無關,即多載的方法不能根據回傳型別進行區分,即外殼不變,核心重寫!
- 多載(overloading) 是在一個類里面,方法名字相同,而引數不同,回傳型別可以相同也可以不同,每個多載的方法(或者建構式)都必須有一個獨一無二的引數型別串列,最常用的地方就是構造器的多載,

22. 多載的方法能否根據回傳值型別進行區分?
不能根據回傳值型別來區分多載的方法,因為呼叫時不指定型別資訊,編譯器不知道你要呼叫哪個函式,
float max(int a, int b);
int max(int a, int b);
當呼叫max(1,2);時無法確定呼叫的是哪個,單從這一點上來說,僅回傳值型別不同的多載是不應該允許的,
23. 構造器(constructor)是否可被重寫(override)?
構造器不能被繼承,因此不能被重寫,但可以被多載,每一個類必須有自己的建構式,負責構造自己這部分的構造,子類不會覆寫父類的建構式,相反必須一開始呼叫父類的建構式,
24. 抽象類和介面的區別是什么?
語法層面上的區別:
- 抽象類可以提供成員方法的實作細節,而介面中只能存在public abstract 方法;
- 抽象類中的成員變數可以是各種型別的,而介面中的成員變數只能是public static final型別的;
- 介面中不能含有靜態代碼塊以及靜態方法,而抽象類可以有靜態代碼塊和靜態方法;
- 一個類只能繼承一個抽象類,而一個類卻可以實作多個介面,
設計層面上的區別:
- 抽象類是對一種事物的抽象,即對類抽象,而介面是對行為的抽象,抽象類是對整個類整體進行抽象,包括屬性、行為,但是介面卻是對類區域(行為)進行抽象,
- 設計層面不同,抽象類作為很多子類的父類,它是一種模板式設計,而介面是一種行為規范,它是一種輻射式設計,
想要深入了解,可以參考這篇文章 :https://www.cnblogs.com/dolphin0520/p/3811437.html
25. 抽象類能使用 final 修飾嗎?
不能,定義抽象類就是讓其他類繼承的,如果定義為 final 該類就不能被繼承,這樣彼此就會產生矛盾,所以 final 不能修飾抽象類
26. java 創建物件有哪幾種方式?
java中提供了以下四種創建物件的方式:
- new創建新物件
- 通過反射機制
- 采用clone機制
- 通過序列化機制
前兩者都需要顯式地呼叫構造方法,對于clone機制,需要注意淺拷貝和深拷貝的區別,對于序列化機制需要明確其實作原理,在java中序列化可以通過實作Externalizable或者Serializable來實作,
27. 什么是不可變物件?好處是什么?
不可變物件指物件一旦被創建,狀態就不能再改變,任何修改都會創建一個新的物件,如 String、Integer及其它包裝類.不可變物件最大的好處是執行緒安全.
28. 能否創建一個包含可變物件的不可變物件?
當然可以,比如final Person[] persons = new Persion[]{}. persons是不可變物件的參考,但其陣列中的Person實體卻是可變的.這種情況下需要特別謹慎,不要共享可變物件的參考.這種情況下,如果資料需要變化時,就回傳原物件的一個拷貝.
29. 值傳遞和參考傳遞的區別的什么?為什么說Java中只有值傳遞?
值傳遞:指的是在方法呼叫時,傳遞的引數是按值的拷貝傳遞,傳遞的是值的拷貝,也就是說傳遞后就互不相關了,
參考傳遞:指的是在方法呼叫時,傳遞的引數是按參考進行傳遞,其實傳遞的是參考的地址,也就是變數所對應的記憶體空間的地址,傳遞的是值的參考,也就是說傳遞前和傳遞后都指向同一個參考(也就是同一個記憶體空間),
基本型別作為引數被傳遞時肯定是值傳遞;參考型別作為引數被傳遞時也是值傳遞,只不過“值”為對應的參考,
想要深入了解,可以參考這篇文章 :http://www.itwanger.com/java/2019/11/26/java-yinyong-value.html
30. == 和 equals 區別是什么?
==常用于相同的基本資料型別之間的比較,也可用于相同型別的物件之間的比較;
- 如果
==比較的是基本資料型別,那么比較的是兩個基本資料型別的值是否相等; - 如果
==是比較的兩個物件,那么比較的是兩個物件的參考,也就是判斷兩個物件是否指向了同一塊記憶體區域;
equals方法主要用于兩個物件之間,檢測一個物件是否等于另一個物件
看一看Object類中equals方法的原始碼:
public boolean equals(Object obj) {
return (this == obj);
}
它的作用也是判斷兩個物件是否相等,般有兩種使用情況:
- 情況1,類沒有覆寫equals()方法,則通過equals()比較該類的兩個物件時,等價于通過“==”比較這兩個物件,
- 情況2,類覆寫了equals()方法,一般,我們都覆寫equals()方法來兩個物件的內容相等;若它們的內容相等,則回傳true(即,認為這兩個物件相等),
java語言規范要求equals方法具有以下特性:
- 自反性,對于任意不為null的參考值x,x.equals(x)一定是true,
- 對稱性),對于任意不為null的參考值x和y,當且僅當x.equals(y)是true時,y.equals(x)也是true,
- 傳遞性,對于任意不為null的參考值x、y和z,如果x.equals(y)是true,同時y.equals(z)是true,那么x.equals(z)一定是true,
- 一致性,對于任意不為null的參考值x和y,如果用于equals比較的物件資訊沒有被修改的話,多次呼叫時x.equals(y)要么一致地回傳true要么一致地回傳false,
- 對于任意不為null的參考值x,x.equals(null)回傳false,
31. 介紹下hashCode()?
hashCode() 的作用是獲取哈希碼,也稱為散列碼;它實際上是回傳一個int整數,這個哈希碼的作用是確定該物件在哈希表中的索引位置,hashCode() 定義在JDK的Object.java中,這就意味著Java中的任何類都包含有hashCode()函式,
散串列存盤的是鍵值對(key-value),它的特點是:能根據“鍵”快速的檢索出對應的“值”,這其中就利用到了散列碼!(可以快速找到所需要的物件)
32. 為什么要有 hashCode?
以“HashSet 如何檢查重復”為例子來說明為什么要有 hashCode:
當你把物件加入 HashSet 時,HashSet 會先計算物件的 hashcode 值來判斷物件加入的位置,同時也會與其他已經加入的物件的 hashcode 值作比較,如果沒有相符的hashcode,HashSet會假設物件沒有重復出現,
但是如果發現有相同 hashcode 值的物件,這時會呼叫 equals()方法來檢查 hashcode 相等的物件是否真的相同,如果兩者相同,HashSet 就不會讓其加入操作成功,如果不同的話,就會重新散列到其他位置,這樣我們就大大減少了 equals 的次數,相應就大大提高了執行速度,
33. hashCode(),equals()兩種方法是什么關系?
Java 對于 eqauls() 方法和 hashCode() 方法是這樣規定的:
- 同一物件上多次呼叫 hashCode() 方法,總是回傳相同的整型值,
- 如果 a.equals(b),則一定有 a.hashCode() 一定等于 b.hashCode(),
- 如果 !a.equals(b),則 a.hashCode() 不一定等于 b.hashCode(),此時如果 a.hashCode() 總是不等于 b.hashCode(),會提高 hashtables 的性能,
- a.hashCode()==b.hashCode() 則 a.equals(b) 可真可假
- a.hashCode()!= b.hashCode() 則 a.equals(b) 為假,
上面結論簡記:
- 如果兩個物件 equals,Java 運行時環境會認為他們的 hashCode 一定相等,
- 如果兩個物件不 equals,他們的 hashCode 有可能相等,
- 如果兩個物件 hashCode 相等,他們不一定 equals,
- 如果兩個物件 hashCode 不相等,他們一定不 equals
補充:關于 equals() 和 hashCode() 的重要規范
- 規范1:若重寫 equals() 方法,有必要重寫 hashcode()方法,確保通過 equals()方法判斷結果為 true 的兩個物件具備相等的 hashcode() 方法回傳值,說得簡單點就是:“如果兩個物件相同,那么他們的 hashCode 應該相等”,不過請注意:這個只是規范,如果非要寫一個類讓 equals() 方法回傳 true 而 hashCode() 方法回傳兩個不相等的值,編譯和運行都是不會報錯的,不過這樣違反了 Java 規范,程式也就埋下了 BUG,
- 規范2:如果 equals() 方法回傳 false,即兩個物件“不相同”,并不要求對這兩個物件呼叫 hashCode() 方法得到兩個不相同的數,說的簡單點就是:“如果兩個物件不相同,他們的 hashCode 可能相同”,
34. 為什么重寫 equals 方法必須重寫 hashcode 方法 ??
斷的時候先根據hashcode進行的判斷,相同的情況下再根據equals()方法進行判斷,如果只重寫了equals方法,而不重寫hashcode的方法,會造成hashcode的值不同,而equals()方法判斷出來的結果為true,
在Java中的一些容器中,不允許有兩個完全相同的物件,插入的時候,如果判斷相同則會進行覆寫,這時候如果只重寫了equals()的方法,而不重寫hashcode的方法,Object中hashcode是根據物件的存盤地址轉換而形成的一個哈希值,這時候就有可能因為沒有重寫hashcode方法,造成相同的物件散列到不同的位置而造成物件的不能覆寫的問題,
35. String,StringBuffer, StringBuilder 的區別是什么?
1.可變與不可變,String類中使用字符陣列保存字串,因為有“final”修飾符,所以string物件是不可變的,對于已經存在的String物件的修改都是重新創建一個新的物件,然后把新的值保存進去.
private final char value[];
StringBuilder與StringBuffer都繼承自AbstractStringBuilder類,在AbstractStringBuilder中也是使用字符陣列保存字串,這兩種物件都是可變的,
char[] value;
2.是否執行緒安全,
String中的物件是不可變的,也就可以理解為常量,顯然執行緒安全,
StringBuilder是非執行緒安全的,
StringBuffer對方法加了同步鎖或者對呼叫的方法加了同步鎖,所以是執行緒安全的,
@Override
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}
3.如果你只是在單執行緒中使用字串緩沖區,那么StringBuilder的效率會更高些,值得注意的是StringBuilder是在JDK1.5版本中增加的,以前版本的JDK不能使用該類,
36. String為什么要設計成不可變的?
1.便于實作字串池(String pool)
在Java中,由于會大量的使用String常量,如果每一次宣告一個String都創建一個String物件,那將會造成極大的空間資源的浪費,Java提出了String pool的概念,在堆中開辟一塊存盤空間String pool,當初始化一個String變數時,如果該字串已經存在了,就不會去創建一個新的字串變數,而是會回傳已經存在了的字串的參考,
String a = "Hello world!";
String b = "Hello world!";
如果字串是可變的,某一個字串變數改變了其值,那么其指向的變數的值也會改變,String pool將不能夠實作!
2.使多執行緒安全
在并發場景下,多個執行緒同時讀一個資源,是安全的,不會引發競爭,但對資源進行寫操作時是不安全的,不可變物件不能被寫,所以保證了多執行緒的安全,
3.避免安全問題
在網路連接和資料庫連接中字串常常作為引數,例如,網路連接地址URL,檔案路徑path,反射機制所需要的String引數,其不可變性可以保證連接的安全性,如果字串是可變的,黑客就有可能改變字串指向物件的值,那么會引起很嚴重的安全問題,
4.加快字串處理速度
由于String是不可變的,保證了hashcode的唯一性,于是在創建物件時其hashcode就可以放心的快取了,不需要重新計算,這也就是Map喜歡將String作為Key的原因,處理速度要快過其它的鍵物件,所以HashMap中的鍵往往都使用String,
總體來說,String不可變的原因要包括 設計考慮,效率優化,以及安全性這三大方面,
參考
https://tech.meituan.com/2019/09/05/java-bytecode-enhancement.html
http://c.biancheng.net/view/769.html
http://www.51gjie.com/java/81.html
http://www.justdojava.com/2019/03/21/Java-and-equals/
https://blog.csdn.net/qq_28051453/article/details/52701171
https://www.cnblogs.com/wkfvawl/p/11693260.html
https://henleylee.github.io/posts/2019/cc1a57ba.html
本文由博客一文多發平臺 OpenWrite 發布!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/261605.html
標籤:Java
