新聞中心
二哥,你好,找工作找了仨月,還沒(méi)有找到,很焦慮,我該怎么辦呢?你那有沒(méi)有 Java 方面的面試題可以分享一波啊?

創(chuàng)新互聯(lián)公司是一家集網(wǎng)站建設(shè),烏恰企業(yè)網(wǎng)站建設(shè),烏恰品牌網(wǎng)站建設(shè),網(wǎng)站定制,烏恰網(wǎng)站建設(shè)報(bào)價(jià),網(wǎng)絡(luò)營(yíng)銷(xiāo),網(wǎng)絡(luò)優(yōu)化,烏恰網(wǎng)站推廣為一體的創(chuàng)新建站企業(yè),幫助傳統(tǒng)企業(yè)提升企業(yè)形象加強(qiáng)企業(yè)競(jìng)爭(zhēng)力??沙浞譂M(mǎn)足這一群體相比中小企業(yè)更為豐富、高端、多元的互聯(lián)網(wǎng)需求。同時(shí)我們時(shí)刻保持專(zhuān)業(yè)、時(shí)尚、前沿,時(shí)刻以成就客戶(hù)成長(zhǎng)自我,堅(jiān)持不斷學(xué)習(xí)、思考、沉淀、凈化自己,讓我們?yōu)楦嗟钠髽I(yè)打造出實(shí)用型網(wǎng)站。
以上是讀者田田給我發(fā)的私信,看完后于我心有戚戚焉啊,最近境況確實(shí)不容樂(lè)觀,并非是個(gè)人的原因造成的。那,既然需要面試題,二哥就義不容辭,必須得準(zhǔn)備一波。
這次我花了一周的時(shí)間,準(zhǔn)備了 31 道 Java 核心面試題,希望能夠幫助到田田,以及其他和田田類(lèi)似情況的讀者朋友。
01、請(qǐng)說(shuō)出 Java 14 版本中更新的重要功能
Java 14 發(fā)布于 2020 年 3 月 17 日,更新的重要功能有:
- switch 表達(dá)式
- instanceof 增強(qiáng)表達(dá)式,預(yù)覽功能
- 文本塊,第二次預(yù)覽
- Records,預(yù)覽功能
剛好我之前寫(xiě)過(guò)一篇文章,關(guān)于 Java 14 的開(kāi)箱體驗(yàn),很香,讀者朋友需要的話(huà),可以點(diǎn)下面的鏈接看一看。
Java 14 開(kāi)箱,它真香香香香
02、請(qǐng)說(shuō)出 Java 13 版本中更新的重要功能
Java 13 發(fā)布于 2019 年 9 月 17 日,更新的重要功能有:
- 文本塊,預(yù)覽功能
- switch 表達(dá)式,預(yù)覽功能
- Java Socket 重新實(shí)現(xiàn)
- FileSystems.newFileSystem() 方法
- 支持 Unicode 12.1
- 可伸縮、低延遲的垃圾收集器改進(jìn),用于返回未使用的內(nèi)存
03、請(qǐng)說(shuō)出 Java 12 版本中更新的重要功能
Java 12 發(fā)布于 2019 年 3 月 19 日,更新的重要功能有:
- JVM 更新
- File.mismatch() 方法
- 緊湊型數(shù)字格式
- String 類(lèi)新增了一些方法,比如說(shuō) indent()
04、請(qǐng)說(shuō)出 Java 11 版本中更新的重要功能
Java 11 是繼 Java 8 之后的第二個(gè)商用版本,如果你下載的是 Oracle JDK,則需要進(jìn)行付費(fèi);如果想繼續(xù)使用免費(fèi)版本,需要下載 Open JDK。
Oracle JDK 中會(huì)有一些 Open JDK 沒(méi)有的、商用閉源的功能。
Java 11 更新的重要功能有:
- 可以直接使用 java 命令運(yùn)行 Java 程序,源代碼將會(huì)隱式編譯和運(yùn)行。
- String 類(lèi)新增了一些方法,比如說(shuō) isBlank()、lines()、strip() 等等。
- Files 類(lèi)新增了兩個(gè)讀寫(xiě)方法,readString() 和 writeString()。
- 可以在 Lambda 表達(dá)式中使用 var 作為變量類(lèi)型。
05、請(qǐng)說(shuō)出 Java 10 版本中更新的重要功能
Java 10 更新的重要功能有:
- 局部變量類(lèi)型推斷,舉個(gè)例子,var list = new ArrayList();,可以使用 var 來(lái)作為變量類(lèi)型,Java 編譯器知道 list 的類(lèi)型為字符串的 ArrayList。
- 增強(qiáng) java.util.Locale。
- 提供了一組默認(rèn)的根證書(shū)頒發(fā)機(jī)構(gòu)(CA)。
06、請(qǐng)說(shuō)出 Java 9 版本中更新的重要功能
Java 9 更新的重要功能有:
- 模塊系統(tǒng)
- 不可變的 List、Set、Map 的工廠(chǎng)方法
- 接口中可以有私有方法
- 垃圾收集器改進(jìn)
07、請(qǐng)說(shuō)出 Java 8 版本中更新的重要功能
Java 8 發(fā)布于 2014 年 3 月份,可以說(shuō)是 Java 6 之后最重要的版本更新,深受開(kāi)發(fā)者的喜愛(ài)。
- 函數(shù)式編程和 Lambda 表達(dá)式
- Stream 流
- Java Date Time API
- 接口中可以使用默認(rèn)方法和靜態(tài)方法
我強(qiáng)烈建議點(diǎn)開(kāi)上面的鏈接閱讀以下,以正確理解這些概念。
08、請(qǐng)說(shuō)出 Java 面向?qū)ο缶幊讨械囊恍┲匾拍?/strong>
- 抽象
- 封裝
- 多態(tài)
- 繼承
09、Java 聲稱(chēng)的平臺(tái)獨(dú)立性指的是什么?
常見(jiàn)的操作系統(tǒng)有 Windows、Linux、OS-X,那么平臺(tái)獨(dú)立性意味著我們可以在任何操作系統(tǒng)中運(yùn)行相同源代碼的 Java 程序,比如說(shuō)我們可以在 Windows 上編寫(xiě) Java 程序,然后在 Linux 上運(yùn)行它。
10、什么是 JVM?
JVM(Java Virtual Machine)俗稱(chēng) Java 虛擬機(jī)。之所以稱(chēng)為虛擬機(jī),是因?yàn)樗鼘?shí)際上并不存在。它提供了一種運(yùn)行環(huán)境,可供 Java 字節(jié)碼在上面運(yùn)行。
JVM 提供了以下操作:
- 加載字節(jié)碼
- 驗(yàn)證字節(jié)碼
- 執(zhí)行字節(jié)碼
- 提供運(yùn)行時(shí)環(huán)境
JVM 定義了以下內(nèi)容:
- 存儲(chǔ)區(qū)
- 類(lèi)文件格式
- 寄存器組
- 垃圾回收堆
- 致命錯(cuò)誤報(bào)告等
我們來(lái)嘗試?yán)斫庖幌?JVM 的內(nèi)部結(jié)構(gòu),它包含了類(lèi)加載器(Class Loader)、運(yùn)行時(shí)數(shù)據(jù)區(qū)(Runtime Data Areas)和執(zhí)行引擎(Excution Engine)。
1)類(lèi)加載器
類(lèi)加載器是 JVM 的一個(gè)子系統(tǒng),用于加載類(lèi)文件。每當(dāng)我們運(yùn)行一個(gè) Java 程序,它都會(huì)由類(lèi)加載器首先加載。Java 中有三個(gè)內(nèi)置的類(lèi)加載器:
- 啟動(dòng)類(lèi)加載器(Bootstrap Class-Loader),加載 jre/lib 包下面的 jar 文件,比如說(shuō)常見(jiàn)的 rt.jar(包含了 Java 標(biāo)準(zhǔn)庫(kù)下的所有類(lèi)文件,比如說(shuō) java.lang 包下的類(lèi),java.net 包下的類(lèi),java.util 包下的類(lèi),java.io 包下的類(lèi),java.sql 包下的類(lèi))。
- 擴(kuò)展類(lèi)加載器(Extension or Ext Class-Loader),加載 jre/lib/ext 包下面的 jar 文件。
- 應(yīng)用類(lèi)加載器(Application or App Clas-Loader),根據(jù)程序的類(lèi)路徑(classpath)來(lái)加載 Java 類(lèi)。
一般來(lái)說(shuō),Java 程序員并不需要直接同類(lèi)加載器進(jìn)行交互。JVM 默認(rèn)的行為就已經(jīng)足夠滿(mǎn)足大多數(shù)情況的需求了。不過(guò),如果遇到了需要和類(lèi)加載器進(jìn)行交互的情況,而對(duì)類(lèi)加載器的機(jī)制又不是很了解的話(huà),就不得不花大量的時(shí)間去調(diào)試
ClassNotFoundException 和 NoClassDefFoundError 等異常。
對(duì)于任意一個(gè)類(lèi),都需要由它的類(lèi)加載器和這個(gè)類(lèi)本身一同確定其在 JVM 中的唯一性。也就是說(shuō),如果兩個(gè)類(lèi)的加載器不同,即使兩個(gè)類(lèi)來(lái)源于同一個(gè)字節(jié)碼文件,那這兩個(gè)類(lèi)就必定不相等(比如兩個(gè)類(lèi)的 Class 對(duì)象不 equals)。
是不是有點(diǎn)暈,來(lái)來(lái)來(lái),通過(guò)一段簡(jiǎn)單的代碼了解下。
- public class Test {
- public static void main(String[] args) {
- ClassLoader loader = Test.class.getClassLoader();
- while (loader != null) {
- System.out.println(loader.toString());
- loaderloader = loader.getParent();
- }
- }
- }
每個(gè) Java 類(lèi)都維護(hù)著一個(gè)指向定義它的類(lèi)加載器的引用,通過(guò) 類(lèi)名.class.getClassLoader() 可以獲取到此引用;然后通過(guò) loader.getParent() 可以獲取類(lèi)加載器的上層類(lèi)加載器。
上面這段代碼的輸出結(jié)果如下:
- sun.misc.Launcher$AppClassLoader@18b4aac2
- sun.misc.Launcher$ExtClassLoader@4617c264
第一行輸出為 Test 的類(lèi)加載器,即應(yīng)用類(lèi)加載器,它是 sun.misc.Launcher$AppClassLoader 類(lèi)的實(shí)例;第二行輸出為擴(kuò)展類(lèi)加載器,是 sun.misc.Launcher$ExtClassLoader 類(lèi)的實(shí)例。那啟動(dòng)類(lèi)加載器呢?
按理說(shuō),擴(kuò)展類(lèi)加載器的上層類(lèi)加載器是啟動(dòng)類(lèi)加載器,但在我這個(gè)版本的 JDK 中, 擴(kuò)展類(lèi)加載器的 getParent() 返回 null。所以沒(méi)有輸出。
2)運(yùn)行時(shí)數(shù)據(jù)區(qū)
運(yùn)行時(shí)數(shù)據(jù)區(qū)又包含以下內(nèi)容。
- PC寄存器(PC Register),也叫程序計(jì)數(shù)器(Program Counter Register),是一塊較小的內(nèi)存空間,它的作用可以看做是當(dāng)前線(xiàn)程所執(zhí)行的字節(jié)碼的信號(hào)指示器。
- JVM 棧(Java Virtual Machine Stack),與 PC 寄存器一樣,JVM 棧也是線(xiàn)程私有的。每一個(gè) JVM 線(xiàn)程都有自己的 JVM 棧,這個(gè)棧與線(xiàn)程同時(shí)創(chuàng)建,它的生命周期與線(xiàn)程相同。
- 本地方法棧(Native Method Stack),JVM 可能會(huì)使用到傳統(tǒng)的棧來(lái)支持 Native 方法(使用 Java 語(yǔ)言以外的其它語(yǔ)言[C語(yǔ)言]編寫(xiě)的方法)的執(zhí)行,這個(gè)棧就是本地方法棧。
- 堆(Heap),在 JVM 中,堆是可供各條線(xiàn)程共享的運(yùn)行時(shí)內(nèi)存區(qū)域,也是供所有類(lèi)實(shí)例和數(shù)據(jù)對(duì)象分配內(nèi)存的區(qū)域。
- 方法區(qū)(Method area),在 JVM 中,被加載類(lèi)型的信息都保存在方法區(qū)中。包括類(lèi)型信息(Type Information)和方法列表(Method Tables)。方法區(qū)是所有線(xiàn)程共享的,所以訪(fǎng)問(wèn)方法區(qū)信息的方法必須是線(xiàn)程安全的。
- 運(yùn)行時(shí)常量池(Runtime Constant Pool),運(yùn)行時(shí)常量池是每一個(gè)類(lèi)或接口的常量池在運(yùn)行時(shí)的表現(xiàn)形式,它包括了編譯器可知的數(shù)值字面量,以及運(yùn)行期解析后才能獲得的方法或字段的引用。簡(jiǎn)而言之,當(dāng)一個(gè)方法或者變量被引用時(shí),JVM 通過(guò)運(yùn)行時(shí)常量區(qū)來(lái)查找方法或者變量在內(nèi)存里的實(shí)際地址。
3)執(zhí)行引擎
執(zhí)行引擎包含了:
- 解釋器:讀取字節(jié)碼流,然后執(zhí)行指令。因?yàn)樗粭l一條地解釋和執(zhí)行指令,所以它可以很快地解釋字節(jié)碼,但是執(zhí)行起來(lái)會(huì)比較慢。
- 即時(shí)(Just-In-Time,JIT)編譯器:即時(shí)編譯器用來(lái)彌補(bǔ)解釋器的缺點(diǎn),提高性能。執(zhí)行引擎首先按照解釋執(zhí)行的方式來(lái)執(zhí)行,然后在合適的時(shí)候,即時(shí)編譯器把整段字節(jié)碼編譯成本地代碼。然后,執(zhí)行引擎就沒(méi)有必要再去解釋執(zhí)行方法了,它可以直接通過(guò)本地代碼去執(zhí)行。執(zhí)行本地代碼比一條一條進(jìn)行解釋執(zhí)行的速度快很多。編譯后的代碼可以執(zhí)行的很快,因?yàn)楸镜卮a是保存在緩存里的。
11、JDK 和 JVM 有什么區(qū)別?
JDK 是 Java Development Kit 的首字母縮寫(xiě),是提供給 Java 開(kāi)發(fā)人員的軟件環(huán)境,包含 JRE 和一組開(kāi)發(fā)工具??煞譃橐韵掳姹荆?/p>
- 標(biāo)準(zhǔn)版(大多數(shù)開(kāi)發(fā)人員用的就是這個(gè))
- 企業(yè)版
- 微型版
JDK 包含了一個(gè)私有的 JVM 和一些其他資源,比如說(shuō)編譯器(javac 命令)、解釋器(java 命令)等,幫助 Java 程序員完成開(kāi)發(fā)工作。
12、JVM 和 JRE 有什么區(qū)別?
Java Runtime Environment(JRE)是 JVM 的實(shí)現(xiàn)。JRE 由 JVM 和 Java 二進(jìn)制文件以及其他類(lèi)組成,可以執(zhí)行任何程序。JRE 不包含 Java 編譯器,調(diào)試器等任何開(kāi)發(fā)工具。
13、哪個(gè)類(lèi)是所有類(lèi)的超類(lèi)?
java.lang.Object 是所有 Java 類(lèi)的超類(lèi),我們不需要繼承它,因?yàn)槭请[式繼承的。
14、為什么 Java 不支持多重繼承?
如果有兩個(gè)類(lèi)共同繼承(extends)一個(gè)有特定方法的父類(lèi),那么該方法會(huì)被兩個(gè)子類(lèi)重寫(xiě)。然后,如果你決定同時(shí)繼承這兩個(gè)子類(lèi),那么在你調(diào)用該重寫(xiě)方法時(shí),編譯器不能識(shí)別你要調(diào)用哪個(gè)子類(lèi)的方法。這也正是著名的菱形問(wèn)題,見(jiàn)下圖。
ClassC 同時(shí)繼承了 ClassA 和 ClassB,ClassC 的對(duì)象在調(diào)用 ClassA 和 ClassB 中重載的方法時(shí),就不知道該調(diào)用 ClassA 的方法,還是 ClassB 的方法。
15、為什么 Java 不是純粹的面向?qū)ο缶幊陶Z(yǔ)言?
之所以不能說(shuō) Java 是純粹的面向?qū)ο缶幊陶Z(yǔ)言,是因?yàn)?Java 支持基本數(shù)據(jù)類(lèi)型,比如說(shuō) int、short、long、double 等,盡管它們有自己的包裝器類(lèi)型,但它們的確不能算是對(duì)象。
16、path 和 classpath 之間有什么區(qū)別?
path 是操作系統(tǒng)用來(lái)查找可執(zhí)行文件的環(huán)境變量,我的電腦上就定義了下圖這些 path 變量,比如 Java 和 Maven 的。
classpath 是針對(duì) Java 而言的,用于指定 Java 虛擬機(jī)載入的字節(jié)碼文件路徑。
17、Java 中 `main()` 方法的重要性是什么?
每個(gè)程序都需要一個(gè)入口,對(duì)于 Java 程序來(lái)說(shuō),入口就是 main 方法。
public static void main(String[] args) {}
- public 關(guān)鍵字是另外一個(gè)訪(fǎng)問(wèn)修飾符,除了可以聲明方法和變量(所有類(lèi)可見(jiàn)),還可以聲明類(lèi)。main() 方法必須聲明為 public。
- static 關(guān)鍵字表示該變量或方法是靜態(tài)變量或靜態(tài)方法,可以直接通過(guò)類(lèi)訪(fǎng)問(wèn),不需要實(shí)例化對(duì)象來(lái)訪(fǎng)問(wèn)。
- void 關(guān)鍵字用于指定方法沒(méi)有返回值。
另外,main 關(guān)鍵字為方法的名字,Java 虛擬機(jī)在執(zhí)行程序時(shí)會(huì)尋找這個(gè)標(biāo)識(shí)符;args 為 main() 方法的參數(shù)名,它的類(lèi)型為一個(gè) String 數(shù)組,也就是說(shuō),在使用 java 命令執(zhí)行程序的時(shí)候,可以給 main() 方法傳遞字符串?dāng)?shù)組作為參數(shù)。
- java HelloWorld 沉默王二 沉默王三
javac 命令用來(lái)編譯程序,java 命令用來(lái)執(zhí)行程序,HelloWorld 為這段程序的類(lèi)名,沉默王二和沉默王三為字符串?dāng)?shù)組,中間通過(guò)空格隔開(kāi),然后就可以在 main() 方法中通過(guò) args[0] 和 args[1] 獲取傳遞的參數(shù)值了。
- public class HelloWorld {
- public static void main(String[] args) {
- if ("沉默王二".equals(args[0])) {
- }
- if ("沉默王三".equals(args[1])) {
- }
- }
- }
main() 方法的寫(xiě)法并不是唯一的,還有其他幾種變體,盡管它們可能并不常見(jiàn),可以簡(jiǎn)單來(lái)了解一下。
第二種,把方括號(hào) [] 往 args 靠近而不是 String 靠近:
- public static void main(String []args) { }
第三種,把方括號(hào) [] 放在 args 的右側(cè):
- public static void main(String args[]) { }
第四種,還可以把數(shù)組形式換成可變參數(shù)的形式:
- public static void main(String...args) { }
第五種,在 main() 方法上添加另外一個(gè)修飾符 strictfp,用于強(qiáng)調(diào)在處理浮點(diǎn)數(shù)時(shí)的兼容性:
- public strictfp static void main(String[] args) { }
也可以在 main() 方法上添加 final 關(guān)鍵字或者 synchronized 關(guān)鍵字。
第六種,還可以為 args 參數(shù)添加 final 關(guān)鍵字:
- public static void main(final String[] args) { }
第七種,最復(fù)雜的一種,所有可以添加的關(guān)鍵字統(tǒng)統(tǒng)添加上:
- final static synchronized strictfp void main(final String[] args) { }
當(dāng)然了,并不需要為了裝逼特意把 main() 方法寫(xiě)成上面提到的這些形式,使用 IDE 提供的默認(rèn)形式就可以了。
18、Java 的重寫(xiě)(Override)和重載(Overload)有什么區(qū)別?
先來(lái)看一段重寫(xiě)的代碼吧。
- class LaoWang{
- public void write() {
- System.out.println("老王寫(xiě)了一本《基督山伯爵》");
- }
- }
- public class XiaoWang extends LaoWang {
- @Override
- public void write() {
- System.out.println("小王寫(xiě)了一本《茶花女》");
- }
- }
重寫(xiě)的兩個(gè)方法名相同,方法參數(shù)的個(gè)數(shù)也相同;不過(guò)一個(gè)方法在父類(lèi)中,另外一個(gè)在子類(lèi)中。就好像父類(lèi) LaoWang 有一個(gè) write() 方法(無(wú)參),方法體是寫(xiě)一本《基督山伯爵》;子類(lèi) XiaoWang 重寫(xiě)了父類(lèi)的 write() 方法(無(wú)參),但方法體是寫(xiě)一本《茶花女》。
來(lái)寫(xiě)一段測(cè)試代碼。
- public class OverridingTest {
- public static void main(String[] args) {
- LaoWang wang = new XiaoWang();
- wang.write();
- }
- }
大家猜結(jié)果是什么?
小王寫(xiě)了一本《茶花女》
在上面的代碼中,們聲明了一個(gè)類(lèi)型為 LaoWang 的變量 wang。在編譯期間,編譯器會(huì)檢查 LaoWang 類(lèi)是否包含了 write() 方法,發(fā)現(xiàn) LaoWang 類(lèi)有,于是編譯通過(guò)。在運(yùn)行期間,new 了一個(gè) XiaoWang 對(duì)象,并將其賦值給 wang,此時(shí) Java 虛擬機(jī)知道 wang 引用的是 XiaoWang 對(duì)象,所以調(diào)用的是子類(lèi) XiaoWang 中的 write() 方法而不是父類(lèi) LaoWang 中的 write() 方法,因此輸出結(jié)果為“小王寫(xiě)了一本《茶花女》”。
再來(lái)看一段重載的代碼吧。
- class LaoWang{
- public void read() {
- System.out.println("老王讀了一本《Web全棧開(kāi)發(fā)進(jìn)階之路》");
- }
- public void read(String bookname) {
- System.out.println("老王讀了一本《" + bookname + "》");
- }
- }
重載的兩個(gè)方法名相同,但方法參數(shù)的個(gè)數(shù)不同,另外也不涉及到繼承,兩個(gè)方法在同一個(gè)類(lèi)中。就好像類(lèi) LaoWang 有兩個(gè)方法,名字都是 read(),但一個(gè)有參數(shù)(書(shū)名),另外一個(gè)沒(méi)有(只能讀寫(xiě)死的一本書(shū))。
來(lái)寫(xiě)一段測(cè)試代碼。
- public class OverloadingTest {
- public static void main(String[] args) {
- LaoWang wang = new LaoWang();
- wang.read();
- wang.read("金瓶梅");
- }
- }
這結(jié)果就不用猜了。變量 wang 的類(lèi)型為 LaoWang,wang.read() 調(diào)用的是無(wú)參的 read() 方法,因此先輸出“老王讀了一本《Web全棧開(kāi)發(fā)進(jìn)階之路》”;wang.read("金瓶") 調(diào)用的是有參的 read(bookname) 方法,因此后輸出“老王讀了一本《金瓶》”。在編譯期間,編譯器就知道這兩個(gè) read() 方法時(shí)不同的,因?yàn)樗鼈兊姆椒ê灻?方法名稱(chēng)+方法參數(shù))不同。
簡(jiǎn)單的來(lái)總結(jié)一下:
1)編譯器無(wú)法決定調(diào)用哪個(gè)重寫(xiě)的方法,因?yàn)橹粡淖兞康念?lèi)型上是無(wú)法做出判斷的,要在運(yùn)行時(shí)才能決定;但編譯器可以明確地知道該調(diào)用哪個(gè)重載的方法,因?yàn)橐妙?lèi)型是確定的,參數(shù)個(gè)數(shù)決定了該調(diào)用哪個(gè)方法。
2)多態(tài)針對(duì)的是重寫(xiě),而不是重載。
- 如果在一個(gè)類(lèi)中有多個(gè)相同名字的方法,但參數(shù)不同,則稱(chēng)為方法重載。
- 父類(lèi)中有一個(gè)方法,子類(lèi)中有另外一個(gè)和它有相同簽名(方法名相同,參數(shù)相同、修飾符相同)的方法時(shí),則稱(chēng)為方法重寫(xiě)。子類(lèi)在重寫(xiě)父類(lèi)方法的時(shí)候可以加一個(gè) @Override 注解。
19、`main()` 方法可以重載嗎?
可以,一個(gè)類(lèi)中可以有多個(gè)名稱(chēng)為“main”的方法:
- public class MainTest {
- public static void main(String[] args) {
- System.out.println("main(String[] args)");
- }
- public static void main(String[] args,String arg) {
- System.out.println("(String[] args,String arg");
- }
- }
但該類(lèi)在運(yùn)行的時(shí)候,只會(huì)找到一個(gè)入口,即 public static void main(String[] args)。
20、一個(gè) Java 源文件中有多個(gè) public 類(lèi)嗎?
一個(gè) Java 源文件中不能有多個(gè) public 類(lèi)。
21、什么是 Java 的 package(包)?
在 Java 中,我們使用 package(包)對(duì)相關(guān)的類(lèi)、接口和子包進(jìn)行分組。這樣做的好處有:
- 使相關(guān)類(lèi)型更容易查找
- 避免命名沖突,比如說(shuō) com.itwanger.Hello 和 com.itwangsan.Hello 不同
- 通過(guò)包和訪(fǎng)問(wèn)權(quán)限控制符來(lái)限定類(lèi)的可見(jiàn)性
可以使用 package 關(guān)鍵字來(lái)定義一個(gè)包名,需要注意的是,這行代碼必須處于一個(gè)類(lèi)中的第一行。強(qiáng)烈建議在包中聲明類(lèi),不要缺省,否則就失去了包結(jié)構(gòu)的帶來(lái)的好處。
包的命名應(yīng)該遵守以下規(guī)則:
- 應(yīng)該全部是小寫(xiě)字母
- 可以包含多個(gè)單詞,單詞之間使用“.”連接,比如說(shuō) java.lang
- 名稱(chēng)由公司名或者組織名確定,采用倒序的方式,比如說(shuō),我個(gè)人博客的域名是 www.itwanger.com,所以我創(chuàng)建的包名是就是 com.itwanger.xxxx。
每個(gè)包或者子包都在磁盤(pán)上有自己的目錄結(jié)構(gòu),如果 Java 文件時(shí)在 com.itwanger.xxxx 包下,那么該文件所在的目錄結(jié)構(gòu)就應(yīng)該是 com->itwanger->xxxx。
默認(rèn)情況下,java.lang 包是默認(rèn)導(dǎo)入的,我們不需要顯式地導(dǎo)入該包下的任何類(lèi)。
- package com.cmower.bb;
- public class PackageTest {
- public static void main(String[] args) {
- Boolean.toString(true);
- }
- }
Boolean 類(lèi)屬于 java.lang 包,當(dāng)使用它的時(shí)候并不需要顯式導(dǎo)入。
22、什么是訪(fǎng)問(wèn)權(quán)限修飾符?
訪(fǎng)問(wèn)權(quán)限修飾符對(duì)于 Java 來(lái)說(shuō),非常重要,目前共有四種:public、private、protected 和 default(缺?。?。
一個(gè)類(lèi)只能使用 public 或者 default 修飾,public 修飾的類(lèi)你之前已經(jīng)見(jiàn)到過(guò)了,現(xiàn)在我來(lái)定義一個(gè)缺省權(quán)限修飾符的類(lèi)給你欣賞一下。
- class Dog {
- }
哈哈,其實(shí)也沒(méi)啥可以欣賞的。缺省意味著這個(gè)類(lèi)可以被同一個(gè)包下的其他類(lèi)進(jìn)行訪(fǎng)問(wèn);而 public 意味著這個(gè)類(lèi)可以被所有包下的類(lèi)進(jìn)行訪(fǎng)問(wèn)。
假如硬要通過(guò) private 和 protected 來(lái)修飾類(lèi)的話(huà),編譯器會(huì)生氣的,它不同意。
private 可以用來(lái)修飾類(lèi)的構(gòu)造方法、字段和方法,只能被當(dāng)前類(lèi)進(jìn)行訪(fǎng)問(wèn)。protected 也可以用來(lái)修飾類(lèi)的構(gòu)造方法、字段和方法,但它的權(quán)限范圍更寬一些,可以被同一個(gè)包中的類(lèi)進(jìn)行訪(fǎng)問(wèn),或者當(dāng)前類(lèi)的子類(lèi)。
可以通過(guò)下面這張圖來(lái)對(duì)比一下四個(gè)權(quán)限修飾符之間的差別:
- 同一個(gè)類(lèi)中,不管是哪種權(quán)限修飾符,都可以訪(fǎng)問(wèn);
- 同一個(gè)包下,private 修飾的無(wú)法訪(fǎng)問(wèn);
- 子類(lèi)可以訪(fǎng)問(wèn) public 和 protected 修飾的;
- public 修飾符面向世界,哈哈,可以被所有的地方訪(fǎng)問(wèn)到。
23、什么是 final 關(guān)鍵字?
final 關(guān)鍵字修飾類(lèi)的時(shí)候,表示該類(lèi)無(wú)法被繼承。比如,String 類(lèi)就是 final 的,無(wú)法被繼承。
final 關(guān)鍵字修飾方法的時(shí)候,表示子類(lèi)無(wú)法覆蓋它。
final 關(guān)鍵字修飾變量的時(shí)候,表示該變量只能被賦值一次,盡管變量的狀態(tài)可以更改。
關(guān)于 final 更詳細(xì)的內(nèi)容,可以參照我之前寫(xiě)了另外一篇文章:
我去,你竟然還不會(huì)用 final 關(guān)鍵字
24、什么是 static 關(guān)鍵字?
static 關(guān)鍵字可以用來(lái)修飾類(lèi)變量,使其具有全局性,即所有對(duì)象將共享同一個(gè)變量。
static 關(guān)鍵字可以用來(lái)修飾方法,該方法稱(chēng)為靜態(tài)方法,只可以訪(fǎng)問(wèn)類(lèi)的靜態(tài)變量,并且只能調(diào)用類(lèi)的靜態(tài)方法。
關(guān)于 static 更詳細(xì)的內(nèi)容,可以參照我之前寫(xiě)了另外一篇文章:
面試官:兄弟,說(shuō)說(shuō)Java的static關(guān)鍵字吧
25、finally 和 finalize 有什么區(qū)別?
finally 通常與 try-catch 塊一起使用,即使 try-catch 塊引發(fā)了異常,finally 塊中的代碼也會(huì)被執(zhí)行,用于釋放 try 塊中創(chuàng)建的資源。
finalize() 是 Object 類(lèi)的一個(gè)特殊方法,當(dāng)對(duì)象正在被垃圾回收時(shí),垃圾收集器將會(huì)調(diào)用該方法。可以重寫(xiě)該方法用于釋放系統(tǒng)資源。
26、可以將一個(gè)類(lèi)聲明為 static 的嗎?
不能將一個(gè)外部類(lèi)聲明為 static 的,但可以將一個(gè)內(nèi)部類(lèi)聲明為 static 的——稱(chēng)為靜態(tài)內(nèi)部類(lèi)。
27、什么是靜態(tài)導(dǎo)入?
如果必須在一個(gè)類(lèi)中使用其他類(lèi)的靜態(tài)變量或者靜態(tài)方法,通常我們需要先導(dǎo)入該類(lèi),然后使用“類(lèi)名.變量/方法”的形式調(diào)用。
- import java.lang.Math;
- double test = Math.PI * 5;
也可以通過(guò)靜態(tài)導(dǎo)入的方式,就不需要再使用類(lèi)名了。
- import static java.lang.Math.PI;
- double test = PI * 5;
不過(guò),靜態(tài)導(dǎo)入容易引發(fā)混亂(變量名或者方法名容易沖突),因此最好避免使用靜態(tài)導(dǎo)入。
28、什么是 try-with-resources?
try-with-resources 是 Java 7 時(shí)引入的一個(gè)自動(dòng)資源管理語(yǔ)句,在此之前,我們必須通過(guò) try-catch-finally 的方式手動(dòng)關(guān)閉資源,當(dāng)我們忘記關(guān)閉資源的時(shí)候,就容易導(dǎo)致內(nèi)存泄漏。
關(guān)于 try-with-resources 更詳細(xì)的內(nèi)容,可以參照我之前寫(xiě)了另外一篇文章:
我去,你竟然還在用 try–catch-finally
29、什么是 multi-catch?
Java 7 改進(jìn)的另外一個(gè)地方就是 multi-catch,可以在單個(gè) catch 中捕獲多個(gè)異常,當(dāng)一個(gè) try 塊拋出多個(gè)類(lèi)似的異常時(shí),這種寫(xiě)法更短,更清晰。
- catch(IOException | SQLException ex){
- logger.error(ex);
- throw new MyException(ex.getMessage());
- }
當(dāng)有多個(gè)異常的時(shí)候,可以使用管道表示符“|”隔開(kāi)。
30、什么是 static 塊?
static 塊是由 Java ClassLoader 將類(lèi)加載到內(nèi)存中時(shí)執(zhí)行的代碼塊。通常用于初始化類(lèi)的靜態(tài)變量或者創(chuàng)建靜態(tài)資源。
31、什么是接口?
接口是 Java 編程語(yǔ)言中的一個(gè)核心概念,不僅在 JDK 源碼中使用很多,還在 Java 設(shè)計(jì)模式、框架和工具中使用很多。接口提供了一種在 Java 中實(shí)現(xiàn)抽象的方法,用于定義子類(lèi)的行為約定。
關(guān)于接口更詳細(xì)的內(nèi)容,可以參照我之前寫(xiě)了另外一篇文章:
可能是把 Java 接口講得最通俗的一篇文章
鳴謝
說(shuō)句實(shí)在話(huà),這 31 道 Java 核心面試題在面試的過(guò)程中還是很常見(jiàn)的,值得好好復(fù)習(xí)一遍。
當(dāng)前題目:31道Java核心面試題,一次性打包送給你
標(biāo)題鏈接:http://www.dlmjj.cn/article/dppcipd.html


咨詢(xún)
建站咨詢(xún)
