java上机面试题 039_深入 Java 虚拟机之面试总结篇
在學(xué)習(xí) JVM 相關(guān)知識(shí),怎么讓自己有動(dòng)力看下去,且有思考性呢?筆者認(rèn)為,開頭用一些常用的面試題,來引入讀者的興趣比較好,這樣才會(huì)有看下去的動(dòng)力。所以,該篇文章會(huì)以面試+總結(jié)的方式,希望讀者能先思考寫出答案,再查看相關(guān)知識(shí)。
一、JVM常見面試題介紹下 Java 內(nèi)存區(qū)域
Java 對(duì)象的創(chuàng)建過程
對(duì)象的訪問定位有幾種
String、StringBuilder、StringBuffer 有什么不同?
這是一些常見的面試,很多人都看到網(wǎng)上的標(biāo)準(zhǔn)答案,但你知道為什么嗎?
1.1 介紹下 Java 內(nèi)存區(qū)域
首先看第一個(gè),Java的內(nèi)存區(qū)域,可以看一張編譯圖:
可以看到Java 的內(nèi)存區(qū)域就是框框里的東西:
總結(jié),建議讀者學(xué)習(xí)之后,能自己默寫這些方法并指導(dǎo)每一步的意思。
1.2 Java 對(duì)象的創(chuàng)建過程
Java 對(duì)象的創(chuàng)建共分為5步,如下圖:
然后明白每個(gè)步驟做了哪些即可,如下:
1.3 對(duì)象的訪問定位有幾種
有兩種方式:句柄和直接指針。
創(chuàng)建對(duì)象是為了使用對(duì)象,虛擬機(jī)需要通過棧中的 reference 來獲取堆上的對(duì)象。
優(yōu)缺點(diǎn): 使用句柄好處是,當(dāng)對(duì)象發(fā)生改變,只需要移動(dòng)句柄的實(shí)例數(shù)據(jù)指針即可,而直接指針就是速度快。
1.4 String、StringBuilder、StringBuffer
參考答案:
String 是用 final 修飾的類,由于它的不可變性,類似拼接、裁剪字符串等,都會(huì)產(chǎn)生新的對(duì)象。
StringBuffer 解決上面拼接對(duì)象而提供一個(gè)類,可以通過 append等方法拼接,是線程安全的,由于線程安全,效率也下降。
StringBuilder 跟StringBuffer 差不多,只是去掉了線程安全,所以優(yōu)先使用 StringBuilder。
說說String 為什么會(huì)產(chǎn)生新的對(duì)象?比如 String a = "1" String b = a + "2",當(dāng)執(zhí)行這條指令時(shí),會(huì)在常量池中產(chǎn)生一個(gè)對(duì)象指向a,而創(chuàng)建b時(shí)也會(huì)重新在常量池中生成b的對(duì)象;多次創(chuàng)建容易觸發(fā) GC,這也是為什么不建議使用 String 類去拼接的問題。
二、Java 回收機(jī)制常見面試題簡(jiǎn)單的介紹一下強(qiáng)引用、軟引用、弱引用、虛引用(虛引用與軟引用和弱引用的區(qū)別、使用軟引用能帶來的好處)
談?wù)刦inal、finally、finalize 有什么不同
方法區(qū)會(huì)回收資源嗎?
垃圾回收有哪些算法,各自的特點(diǎn)?
2.1 強(qiáng)引用、軟引用、弱引用、虛引用
首先,在講解這幾個(gè)引用之前,先明白虛擬機(jī)為什么會(huì)由這些引用的說明;我們都知道,對(duì)象需要回收,那怎么去判斷哪些對(duì)象需要回收呢?這就需要一些判斷來確定哪些對(duì)象是需要回收的,一般有以下幾種方法:
無論是 引用計(jì)算算法還是可達(dá)性分析算法,都是涉及到對(duì)象的引用問題,所以,在 JDK1.2 之后,又分為以下幾類引用:
通過上面的介紹,知道了"引用"是什么關(guān)系,這對(duì)理解各種引用還是很有必要的,那么使用 軟引用的好處也在那里了,建議一些內(nèi)存消耗較大的使用軟引用,比如 webview。
2.2 談?wù)刦inal、finally、finalize 有什么不同
final 和finally 比較好理解。首先 final 用來修飾的對(duì)象不可變;finally 則是保證重點(diǎn)代碼一定要被執(zhí)行的一種機(jī)制,一般用于 try - catch-finally 語句中。
但finalize 是什么東西呢?在解釋標(biāo)準(zhǔn)代碼之前,又得回到GC算法中了。
首先,finalize 是 Object 的一個(gè)方法,用來特定資源的回收。上面說到,當(dāng) GC Roots 不可達(dá)時(shí),認(rèn)為對(duì)象已經(jīng)不再使用了,但是對(duì)象并非是非"死"不可,當(dāng) GC Roots 不可達(dá)時(shí),系統(tǒng)首先會(huì)先判斷 對(duì)象的 finalize 是否執(zhí)行,不執(zhí)行則直接回收。如果可以執(zhí)行,則放在隊(duì)列中,由finalize線程去執(zhí)行它,如果有其他對(duì)象關(guān)聯(lián)時(shí),則判斷對(duì)象不可回收,否則對(duì)象回收,finalize 執(zhí)行一次,如下圖:
由于它的不確定性,在 JDK9時(shí),已經(jīng)標(biāo)注為deprecated,但不影響我們對(duì)它的理解。
2.3 方法區(qū)會(huì)回收資源嗎?
雖說 Java 堆 可以回收70%~95%的空間,但方法區(qū)同樣可以回收一些資源,方法區(qū)主要回收兩個(gè)部分廢棄常量和無用的類。
所以,當(dāng)發(fā)生 GC 時(shí),非常常量和無用類是可以被回收,當(dāng)然這里也是說"可以",是否像對(duì)象一樣被回收,還需要對(duì)虛擬機(jī)的參數(shù)配置,這里就不細(xì)說了。
2.4 垃圾回收有哪些算法,各自的特點(diǎn)?
對(duì)象的回收,基于上面講到的,GC Roots不可達(dá),且判斷可以回收。衍生的算法如下圖(建議能默認(rèn)每種算法的理解):
其中,基礎(chǔ)是 標(biāo)記-清除是基礎(chǔ),接下來都是在它的基礎(chǔ)上改進(jìn),分代算法是主流 Java 虛擬機(jī)的主要算法。
三、類加載的問題類加載過程
寫出下列代碼打印信息,若將System.out.println(Child.c_value)改為System.out.println(Child.value)會(huì)如何?public?class?Parent{
static?{
System.out.println("Parent");
}
public?static?int?value?=?123;
}
public?class?Child?extends?Parent{
static?{
System.out.println("Child");
}
public?static?int?c_value?=?123;
}
//mian?中執(zhí)行
public?static?void?main(String[]?args)?{
System.out.println(Child.c_value);
}說說你對(duì)類加載器的理解
什么是雙親委派模型
3.1 類加載的過程
類加載的過程如下圖所示(建議能默認(rèn)每個(gè)步驟的理解):
也可以成為 加載-連接-初始化 這種叫法。
其中,加載、驗(yàn)證、準(zhǔn)備、初始化和卸載的順序是固定的,而解析則不一定,因?yàn)镴ava是動(dòng)態(tài)語言,它可以在運(yùn)行時(shí)解析,即初始化之后。該階段解析如下:
3.2 Child.value和Child.c_valuepublic?class?Parent{
static?{
System.out.println("Parent");
}
public?static?int?value?=?123;
}
public?class?Child?extends?Parent{
static?{
System.out.println("Child");
}
public?static?int?c_value?=?123;
}
//mian?中執(zhí)行
public?static?void?main(String[]?args)?{
System.out.println(Child.c_value);
}
打印信息如:Parent
123
改為System.out.println(Child.value)時(shí):Parent
Child
123
擴(kuò)展:class?Parent{
public?static?int?value?=?1;
static?{
value?=?2;
}
}
class?Child?extends?Parent{
public?static?int?B?=?value?;
}
public?static?void?main(String[]?args)?{
System.out.println(Child.B);
}
輸出什么?
3.3 說說你對(duì)類加載器的理解
從上面我們知道,類在加載的時(shí)候,就是通過一個(gè)全限定名去加載這個(gè)類的二進(jìn)制字節(jié)流,這個(gè)是系統(tǒng)自動(dòng)完成的。這個(gè)動(dòng)作如果從外部去做,以便于我們?nèi)カ@取所需的類,則我們成為類加載器。比如通過一個(gè)路徑獲取到一個(gè) class 字節(jié)碼,然后通過反射,拿到相應(yīng)的信息。
3.4 什么是雙親委派模型
它的工程流程是:當(dāng)一個(gè)類加載器收到類加載的請(qǐng)求,它首先不會(huì)自己去嘗試加載這個(gè)類,而是委派給她的父類加載器去完成,每一個(gè)層次的類加載器都是如此,因此所有的加載器都會(huì)傳遞到父加載器中。只有父加載器無法完成時(shí),子加載器才會(huì)嘗試自己去加載,它的模型如下:
類加載雙親委派模型
總結(jié)
以上是生活随笔為你收集整理的java上机面试题 039_深入 Java 虚拟机之面试总结篇的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java 生成缩略图类_JAVA生成【缩
- 下一篇: java获取数组的最小值_Java 数组