溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

今天帶你們分析一下java深入源碼級(jí)的面試題

發(fā)布時(shí)間:2020-07-11 17:23:37 來(lái)源:網(wǎng)絡(luò) 閱讀:381 作者:Android丶VG 欄目:移動(dòng)開(kāi)發(fā)

今天雙11剁手節(jié),祝大家節(jié)日快樂(lè)

今天和大家一起分析一下那些面試中可能會(huì)問(wèn)到的java深入源碼級(jí)的面試題

對(duì)此很多面試中遇到的問(wèn)題,花了15個(gè)小時(shí)整理成為了一份983頁(yè)的PDF文檔。
今天帶你們分析一下java深入源碼級(jí)的面試題
今天帶你們分析一下java深入源碼級(jí)的面試題

(更多完整項(xiàng)目下載。未完待續(xù)。源碼。圖文知識(shí)后續(xù)上傳github。)
可以點(diǎn)擊關(guān)于我聯(lián)系我獲取完整PDF
(VX:×××)

1、哪些情況下的對(duì)象會(huì)被垃圾回收機(jī)制處理掉?

利用可達(dá)性分析算法,虛擬機(jī)會(huì)將一些對(duì)象定義為GC Roots,從GC Roots出發(fā)沿著引用鏈向下尋找,如果某個(gè)對(duì)象不能通過(guò)GC Roots尋找到,虛擬機(jī)就認(rèn)為該對(duì)象可以被回收掉。

1.1 哪些對(duì)象可以被看做是GC Roots呢?

1)虛擬機(jī)棧(棧幀中的本地變量表)中引用的對(duì)象;

2)方法區(qū)中的類(lèi)靜態(tài)屬性引用的對(duì)象,常量引用的對(duì)象;

3)本地方法棧中JNI(Native方法)引用的對(duì)象;

1.2 對(duì)象不可達(dá),一定會(huì)被垃圾收集器回收么?

即使不可達(dá),對(duì)象也不一定會(huì)被垃圾收集器回收,
1)先判斷對(duì)象是否有必要執(zhí)行finalize()方法,對(duì)象必須重寫(xiě)finalize()方法且沒(méi)有被運(yùn)行過(guò)。

2)若有必要執(zhí)行,會(huì)把對(duì)象放到一個(gè)隊(duì)列中,JVM會(huì)開(kāi)一個(gè)線(xiàn)程去回收它們,這是對(duì)象最后一次可以逃逸清理的機(jī)會(huì)。

2、講一下常見(jiàn)編碼方式?

編碼的意義:計(jì)算機(jī)中存儲(chǔ)的最小單元是一個(gè)字節(jié)即8bit,所能表示的字符范圍是255個(gè),而人類(lèi)要表示的符號(hào)太多,無(wú)法用一個(gè)字節(jié)來(lái)完全表示,固需要將符號(hào)編碼,將各種語(yǔ)言翻譯成計(jì)算機(jī)能懂的語(yǔ)言。

1)ASCII碼:總共128個(gè),用一個(gè)字節(jié)的低7位表示,0?31控制字符如換回車(chē)刪除等;32~126是打印字符,可通過(guò)鍵盤(pán)輸入并顯示出來(lái);

2)ISO-8859-1,用來(lái)擴(kuò)展ASCII編碼,256個(gè)字符,涵蓋了大多數(shù)西歐語(yǔ)言字符。

3)GB2312:雙字節(jié)編碼,總編碼范圍是A1-A7,A1-A9是符號(hào)區(qū),包含682個(gè)字符,B0-B7是漢字區(qū),包含6763個(gè)漢字;

4)GBK為了擴(kuò)展GB2312,加入了更多的漢字,編碼范圍是8140~FEFE,有23940個(gè)碼位,能表示21003個(gè)漢字。

5)UTF-16: ISO試圖想創(chuàng)建一個(gè)全新的超語(yǔ)言字典,世界上所有語(yǔ)言都可通過(guò)這本字典Unicode來(lái)相互翻譯,而UTF-16定義了Unicode字符在計(jì)算機(jī)中存取方法,用兩個(gè)字節(jié)來(lái)表示Unicode轉(zhuǎn)化格式。不論什么字符都可用兩字節(jié)表示,即16bit,固叫UTF-16。

6)UTF-8:UTF-16統(tǒng)一采用兩字節(jié)表示一個(gè)字符,但有些字符只用一個(gè)字節(jié)就可表示,浪費(fèi)存儲(chǔ)空間,而UTF-8采用一種變長(zhǎng)技術(shù),每個(gè)編碼區(qū)域有不同的字碼長(zhǎng)度。? 不同類(lèi)型的字符可以由1~6個(gè)字節(jié)組成。? ? ? ? ? ? ? ? ? ?

3、utf-8編碼中的中文占幾個(gè)字節(jié);int型幾個(gè)字節(jié)?

utf-8是一種變長(zhǎng)編碼技術(shù),utf-8編碼中的中文占用的字節(jié)不確定,可能2個(gè)、3個(gè)、4個(gè),int型占4個(gè)字節(jié)。

4、靜態(tài)代理和動(dòng)態(tài)代理的區(qū)別,什么場(chǎng)景使用?

代理是一種常用的設(shè)計(jì)模式,目的是:為其他對(duì)象提供一個(gè)代理以控制對(duì)某個(gè)對(duì)象的訪問(wèn),將兩個(gè)類(lèi)的關(guān)系解耦。代理類(lèi)和委托類(lèi)都要實(shí)現(xiàn)相同的接口,因?yàn)榇碚嬲{(diào)用的是委托類(lèi)的方法。

區(qū)別:

1)靜態(tài)代理:由程序員創(chuàng)建或是由特定工具生成,在代碼編譯時(shí)就確定了被代理的類(lèi)是哪一個(gè)是靜態(tài)代理。靜態(tài)代理通常只代理一個(gè)類(lèi);

2)動(dòng)態(tài)代理:在代碼運(yùn)行期間,運(yùn)用反射機(jī)制動(dòng)態(tài)創(chuàng)建生成。動(dòng)態(tài)代理代理的是一個(gè)接口下的多個(gè)實(shí)現(xiàn)類(lèi);

實(shí)現(xiàn)步驟:a.實(shí)現(xiàn)InvocationHandler接口創(chuàng)建自己的調(diào)用處理器;b.給Proxy類(lèi)提供ClassLoader和代理接口類(lèi)型數(shù)組創(chuàng)建動(dòng)態(tài)代理類(lèi);c.利用反射機(jī)制得到動(dòng)態(tài)代理類(lèi)的構(gòu)造函數(shù);d.利用動(dòng)態(tài)代理類(lèi)的構(gòu)造函數(shù)創(chuàng)建動(dòng)態(tài)代理類(lèi)對(duì)象;

使用場(chǎng)景:Retrofit中直接調(diào)用接口的方法;Spring的AOP機(jī)制;

5、Java的異常體系

Java中Throwable是所有異常和錯(cuò)誤的超類(lèi),兩個(gè)直接子類(lèi)是Error(錯(cuò)誤)和Exception(異常):

1)Error是程序無(wú)法處理的錯(cuò)誤,由JVM產(chǎn)生和拋出,如OOM、ThreadDeath等。這些異常發(fā)生時(shí),JVM一般會(huì)選擇終止程序。

2)Exception是程序本身可以處理的異常,又分為運(yùn)行時(shí)異常(RuntimeException)(也叫Checked Eception)和非運(yùn)行時(shí)異常(不檢查異常Unchecked Exception)。運(yùn)行時(shí)異常有NullPointerException\IndexOutOfBoundsException等,這些異常一般是由程序邏輯錯(cuò)誤引起的,應(yīng)盡可能避免。非運(yùn)行時(shí)異常有IOException`SQLException\FileNotFoundException`以及由用戶(hù)自定義的Exception異常等。

6、談?wù)勀銓?duì)解析與分派的認(rèn)識(shí)。

解析指方法在運(yùn)行前,即編譯期間就可知的,有一個(gè)確定的版本,運(yùn)行期間也不會(huì)改變。解析是靜態(tài)的,在類(lèi)加載的解析階段就可將符號(hào)引用轉(zhuǎn)變成直接引用。

分派可分為靜態(tài)分派和動(dòng)態(tài)分派,重載屬于靜態(tài)分派,覆蓋屬于動(dòng)態(tài)分派。靜態(tài)分派是指在重載時(shí)通過(guò)參數(shù)的靜態(tài)類(lèi)型而非實(shí)際類(lèi)型作為判斷依據(jù),在編譯階段,編譯器可根據(jù)參數(shù)的靜態(tài)類(lèi)型決定使用哪一個(gè)重載版本。動(dòng)態(tài)分派則需要根據(jù)實(shí)際類(lèi)型來(lái)調(diào)用相應(yīng)的方法。 ? ? ?

7、修改對(duì)象A的equals方法的簽名,那么使用HashMap存放這個(gè)對(duì)象實(shí)例的時(shí)候,會(huì)調(diào)用哪個(gè)equals方法?

會(huì)調(diào)用對(duì)象的equals方法,如果對(duì)象的equals方法沒(méi)有被重寫(xiě),equals方法和==都是比較棧內(nèi)局部變量表中指向堆內(nèi)存地址值是否相等。

8、Java中實(shí)現(xiàn)多態(tài)的機(jī)制是什么?

多態(tài)是指程序中定義的引用變量所指向的具體類(lèi)型和通過(guò)該引用變量發(fā)出的方法調(diào)用在編譯時(shí)不確定,在運(yùn)行期間才確定,一個(gè)引用變量到底會(huì)指向哪個(gè)類(lèi)的實(shí)例。這樣就可以不用修改源程序,就可以讓引用變量綁定到各種不同的類(lèi)實(shí)現(xiàn)上。

Java實(shí)現(xiàn)多態(tài)有三個(gè)必要條件:繼承、重定、向上轉(zhuǎn)型,在多態(tài)中需要將子類(lèi)的引用賦值給父類(lèi)對(duì)象,只有這樣該引用才能夠具備調(diào)用父類(lèi)方法和子類(lèi)的方法。

9、如何將一個(gè)Java對(duì)象序列化到文件里?

ObjectOutputStream.writeObject()負(fù)責(zé)將指定的流寫(xiě)入,ObjectInputStream.readObject()從指定流讀取序列化數(shù)據(jù)。? ? ?

?//寫(xiě)入
try {
    ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("D:/student.txt"));
    os.writeObject(studentList);
    os.close();
} catch(FileNotFoundException e) {
    e.printStackTrace();
} catch(IOException e) {
    e.printStackTrace();
}

10、說(shuō)說(shuō)你對(duì)Java反射的理解

在運(yùn)行狀態(tài)中,對(duì)任意一個(gè)類(lèi),都能知道這個(gè)類(lèi)的所有屬性和方法,對(duì)任意一個(gè)對(duì)象,都能調(diào)用它的任意一個(gè)方法和屬性。這種能動(dòng)態(tài)獲取信息及動(dòng)態(tài)調(diào)用對(duì)象方法的功能稱(chēng)為java語(yǔ)言的反射機(jī)制。

反射的作用:開(kāi)發(fā)過(guò)程中,經(jīng)常會(huì)遇到某個(gè)類(lèi)的某個(gè)成員變量、方法或?qū)傩允撬接械?,或只?duì)系統(tǒng)應(yīng)用開(kāi)放,這里就可以利用java的反射機(jī)制通過(guò)反射來(lái)獲取所需的私有成員或是方法。

1) 獲取類(lèi)的Class對(duì)象實(shí)例 Class clz = Class.forName("com.zhenai.api.Apple");

2) 根據(jù)Class對(duì)象實(shí)例獲取Constructor對(duì)象? Constructor appConstructor = clz.getConstructor();

3) 使用Constructor對(duì)象的newInstance方法獲取反射類(lèi)對(duì)象 Object appleObj = appConstructor.newInstance();

4) 獲取方法的Method對(duì)象? Method setPriceMethod = clz.getMethod("setPrice", int.class);

5) 利用invoke方法調(diào)用方法? setPriceMethod.invoke(appleObj, 14);

6) 通過(guò)getFields()可以獲取Class類(lèi)的屬性,但無(wú)法獲取私有屬性,而getDeclaredFields()可以獲取到包括私有屬性在內(nèi)的所有屬性。帶有Declared修飾的方法可以反射到私有的方法,沒(méi)有Declared修飾的只能用來(lái)反射公有的方法,其他如Annotation`Field\Constructor`也是如此。

11、說(shuō)說(shuō)你對(duì)Java注解的理解

注解是通過(guò)@interface關(guān)鍵字來(lái)進(jìn)行定義的,形式和接口差不多,只是前面多了一個(gè)@

public @interface TestAnnotation {
}

使用時(shí)@TestAnnotation來(lái)引用,要使注解能正常工作,還需要使用元注解,它是可以注解到注解上的注解。元標(biāo)簽有@Retention?@Documented @Target @Inherited @Repeatable五種

@Retention說(shuō)明注解的存活時(shí)間,取值有RetentionPolicy.SOURCE注解只在源碼階段保留,在編譯器進(jìn)行編譯時(shí)被丟棄;RetentionPolicy.CLASS 注解只保留到編譯進(jìn)行的時(shí)候,并不會(huì)被加載到JVM中。RetentionPolicy.RUNTIME可以留到程序運(yùn)行的時(shí)候,它會(huì)被加載進(jìn)入到JVM中,所以在程序運(yùn)行時(shí)可以獲取到它們。

@Documented 注解中的元素包含到javadoc中去

@Target? 限定注解的應(yīng)用場(chǎng)景,ElementType.FIELD給屬性進(jìn)行注解;ElementType.LOCAL_VARIABLE可以給局部變量進(jìn)行注解;ElementType.METHOD可以給方法進(jìn)行注解;ElementType.PACKAGE可以給一個(gè)包進(jìn)行注解 ElementType.TYPE可以給一個(gè)類(lèi)型進(jìn)行注解,如類(lèi)、接口、枚舉

@Inherited 若一個(gè)超類(lèi)被@Inherited注解過(guò)的注解進(jìn)行注解,它的子類(lèi)沒(méi)有被任何注解應(yīng)用的話(huà),該子類(lèi)就可繼承超類(lèi)的注解;

注解的作用:

1)提供信息給編譯器:編譯器可利用注解來(lái)探測(cè)錯(cuò)誤和警告信息

2)編譯階段:軟件工具可以利用注解信息來(lái)生成代碼、html文檔或做其它相應(yīng)處理;

3)運(yùn)行階段:程序運(yùn)行時(shí)可利用注解提取代碼

注解是通過(guò)反射獲取的,可以通過(guò)Class對(duì)象的isAnnotationPresent()方法判斷它是否應(yīng)用了某個(gè)注解,再通過(guò)getAnnotation()方法獲取Annotation對(duì)象

12、說(shuō)一下泛型原理,并舉例說(shuō)明

泛型就是將類(lèi)型變成參數(shù)傳入,使得可以使用的類(lèi)型多樣化,從而實(shí)現(xiàn)解耦。Java泛型是在Java1.5以后出現(xiàn)的,為保持對(duì)以前版本的兼容,使用了擦除的方法實(shí)現(xiàn)泛型。擦除是指在一定程度無(wú)視類(lèi)型參數(shù)T,直接從T所在的類(lèi)開(kāi)始向上T的父類(lèi)去擦除,如調(diào)用泛型方法,傳入類(lèi)型參數(shù)T進(jìn)入方法內(nèi)部,若沒(méi)在聲明時(shí)做類(lèi)似public T methodName(T extends Father t){},Java就進(jìn)行了向上類(lèi)型的擦除,直接把參數(shù)t當(dāng)做Object類(lèi)來(lái)處理,而不是傳進(jìn)去的T。

即在有泛型的任何類(lèi)和方法內(nèi)部,它都無(wú)法知道自己的泛型參數(shù),擦除和轉(zhuǎn)型都是在邊界上發(fā)生,即傳進(jìn)去的參在進(jìn)入類(lèi)或方法時(shí)被擦除掉,但傳出來(lái)的時(shí)候又被轉(zhuǎn)成了我們?cè)O(shè)置的T。在泛型類(lèi)或方法內(nèi),任何涉及到具體類(lèi)型(即擦除后的類(lèi)型的子類(lèi))操作都不能進(jìn)行,如new T(),或者T.play()(play為某子類(lèi)的方法而不是擦除后的類(lèi)的方法)

13、Java中String的了解

1)String類(lèi)是final型,固String類(lèi)不能被繼承,它的成員方法也都默認(rèn)為final方法。String對(duì)象一旦創(chuàng)建就固定不變了,對(duì)String對(duì)象的任何改變都不影響到原對(duì)象,相關(guān)的任何改變操作都會(huì)生成新的String對(duì)象。

2)String類(lèi)是通過(guò)char數(shù)組來(lái)保存字符串的,String對(duì)equals方法進(jìn)行了重定,比較的是值相等。

String a = "test"; String b = "test"; String c = new String("test");

a、b和字面上的test都是指向JVM字符串常量池中的"test"對(duì)象,他們指向同一個(gè)對(duì)象。而new關(guān)鍵字一定會(huì)產(chǎn)生一個(gè)對(duì)象test,該對(duì)象存儲(chǔ)在堆中。所以new String("test")產(chǎn)生了兩個(gè)對(duì)象,保存在棧中的c和保存在堆中的test。而在java中根本就不存在兩個(gè)完全一模一樣的字符串對(duì)象,故在堆中的test應(yīng)該是引用字符串常量池中的test。

例:

String str1 = "abc"; //棧中開(kāi)辟一塊空間存放引用str1,str1指向池中String常量"abc"
String str2 = "def"; //棧中開(kāi)辟一塊空間存放引用str2,str2指向池中String常量"def"
String str3 = str1 + str2;//棧中開(kāi)辟一塊空間存放引用str3
//str1+str2通過(guò)StringBuilder的最后一步toString()方法返回一個(gè)新的String對(duì)象"abcdef"
//會(huì)在堆中開(kāi)辟一塊空間存放此對(duì)象,引用str3指向堆中的(str1+str2)所返回的新String對(duì)象。
System.out.println(str3 == "abcdef");//返回false
因?yàn)閟tr3指向堆中的"abcdef"對(duì)象,而"abcdef"是字符池中的對(duì)象,所以結(jié)果為false。JVM對(duì)String str="abc"對(duì)象放在常量池是在編譯時(shí)做的,而String str3=str1+str2是在運(yùn)行時(shí)才知道的,new對(duì)象也是在運(yùn)行時(shí)才做的。

14、String為什么要設(shè)計(jì)成不可變的?

1)字符串常量池需要String不可變。
因?yàn)镾tring設(shè)計(jì)成不可變,當(dāng)創(chuàng)建一個(gè)String對(duì)象時(shí),若此字符串值已經(jīng)存在于常量池中,則不會(huì)創(chuàng)建一個(gè)新的對(duì)象,而是引用已經(jīng)存在的對(duì)象。如果字符串變量允許必變,會(huì)導(dǎo)致各種邏輯錯(cuò)誤,如改變一個(gè)對(duì)象會(huì)影響到另一個(gè)獨(dú)立對(duì)象。

2)String對(duì)象可以緩存hashCode。
字符串的不可變性保證了hash碼的唯一性,因此可以緩存String的hashCode,這樣不用每次去重新計(jì)算哈希碼。在進(jìn)行字符串比較時(shí),可以直接比較hashCode,提高了比較性能;

3)安全性。
String被許多java類(lèi)用來(lái)當(dāng)作參數(shù),如url地址,文件path路徑,反射機(jī)制所需的Strign參數(shù)等,若String可變,將會(huì)引起各種安全隱患。 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

(更多完整項(xiàng)目下載。未完待續(xù)。源碼。圖文知識(shí)后續(xù)上傳github。)
可以點(diǎn)擊關(guān)于我聯(lián)系我獲取完整PDF
(VX:×××)

今天帶你們分析一下java深入源碼級(jí)的面試題

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI