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

今天雙11剁手節,祝大家節日快樂

今天和大家一起分析一下那些面試中可能會問到的java深入源碼級的面試題

對此很多面試中遇到的問題,花了15個小時整理成爲了一份983頁的PDF文檔。
今天帶你們分析一下java深入源碼級的面試題
今天帶你們分析一下java深入源碼級的面試題

(更多完整項目下載。未完待續。源碼。圖文知識後續上傳github。)
可以點擊關於我聯繫我獲取完整PDF
(VX:×××)

1、哪些情況下的對象會被垃圾回收機制處理掉?

利用可達性分析算法,虛擬機會將一些對象定義爲GC Roots,從GC Roots出發沿着引用鏈向下尋找,如果某個對象不能通過GC Roots尋找到,虛擬機就認爲該對象可以被回收掉。

1.1 哪些對象可以被看做是GC Roots呢?

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

2)方法區中的類靜態屬性引用的對象,常量引用的對象;

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

1.2 對象不可達,一定會被垃圾收集器回收麼?

即使不可達,對象也不一定會被垃圾收集器回收,
1)先判斷對象是否有必要執行finalize()方法,對象必須重寫finalize()方法且沒有被運行過。

2)若有必要執行,會把對象放到一個隊列中,JVM會開一個線程去回收它們,這是對象最後一次可以逃逸清理的機會。

2、講一下常見編碼方式?

編碼的意義:計算機中存儲的最小單元是一個字節即8bit,所能表示的字符範圍是255個,而人類要表示的符號太多,無法用一個字節來完全表示,固需要將符號編碼,將各種語言翻譯成計算機能懂的語言。

1)ASCII碼:總共128個,用一個字節的低7位表示,0〜31控制字符如換回車刪除等;32~126是打印字符,可通過鍵盤輸入並顯示出來;

2)ISO-8859-1,用來擴展ASCII編碼,256個字符,涵蓋了大多數西歐語言字符。

3)GB2312:雙字節編碼,總編碼範圍是A1-A7,A1-A9是符號區,包含682個字符,B0-B7是漢字區,包含6763個漢字;

4)GBK爲了擴展GB2312,加入了更多的漢字,編碼範圍是8140~FEFE,有23940個碼位,能表示21003個漢字。

5)UTF-16: ISO試圖想創建一個全新的超語言字典,世界上所有語言都可通過這本字典Unicode來相互翻譯,而UTF-16定義了Unicode字符在計算機中存取方法,用兩個字節來表示Unicode轉化格式。不論什麼字符都可用兩字節表示,即16bit,固叫UTF-16。

6)UTF-8:UTF-16統一採用兩字節表示一個字符,但有些字符只用一個字節就可表示,浪費存儲空間,而UTF-8採用一種變長技術,每個編碼區域有不同的字碼長度。  不同類型的字符可以由1~6個字節組成。                   

3、utf-8編碼中的中文佔幾個字節;int型幾個字節?

utf-8是一種變長編碼技術,utf-8編碼中的中文佔用的字節不確定,可能2個、3個、4個,int型佔4個字節。

4、靜態代理和動態代理的區別,什麼場景使用?

代理是一種常用的設計模式,目的是:爲其他對象提供一個代理以控制對某個對象的訪問,將兩個類的關係解耦。代理類和委託類都要實現相同的接口,因爲代理真正調用的是委託類的方法。

區別:

1)靜態代理:由程序員創建或是由特定工具生成,在代碼編譯時就確定了被代理的類是哪一個是靜態代理。靜態代理通常只代理一個類;

2)動態代理:在代碼運行期間,運用反射機制動態創建生成。動態代理代理的是一個接口下的多個實現類;

實現步驟:a.實現InvocationHandler接口創建自己的調用處理器;b.給Proxy類提供ClassLoader和代理接口類型數組創建動態代理類;c.利用反射機制得到動態代理類的構造函數;d.利用動態代理類的構造函數創建動態代理類對象;

使用場景:Retrofit中直接調用接口的方法;Spring的AOP機制;

5、Java的異常體系

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

1)Error是程序無法處理的錯誤,由JVM產生和拋出,如OOMThreadDeath等。這些異常發生時,JVM一般會選擇終止程序。

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

6、談談你對解析與分派的認識。

解析指方法在運行前,即編譯期間就可知的,有一個確定的版本,運行期間也不會改變。解析是靜態的,在類加載的解析階段就可將符號引用轉變成直接引用。

分派可分爲靜態分派和動態分派,重載屬於靜態分派,覆蓋屬於動態分派。靜態分派是指在重載時通過參數的靜態類型而非實際類型作爲判斷依據,在編譯階段,編譯器可根據參數的靜態類型決定使用哪一個重載版本。動態分派則需要根據實際類型來調用相應的方法。      

7、修改對象A的equals方法的簽名,那麼使用HashMap存放這個對象實例的時候,會調用哪個equals方法?

會調用對象的equals方法,如果對象的equals方法沒有被重寫,equals方法和==都是比較棧內局部變量表中指向堆內存地址值是否相等。

8、Java中實現多態的機制是什麼?

多態是指程序中定義的引用變量所指向的具體類型和通過該引用變量發出的方法調用在編譯時不確定,在運行期間才確定,一個引用變量到底會指向哪個類的實例。這樣就可以不用修改源程序,就可以讓引用變量綁定到各種不同的類實現上。

Java實現多態有三個必要條件:繼承、重定、向上轉型,在多態中需要將子類的引用賦值給父類對象,只有這樣該引用才能夠具備調用父類方法和子類的方法。

9、如何將一個Java對象序列化到文件裏?

ObjectOutputStream.writeObject()負責將指定的流寫入,ObjectInputStream.readObject()從指定流讀取序列化數據。     

 //寫入
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、說說你對Java反射的理解

在運行狀態中,對任意一個類,都能知道這個類的所有屬性和方法,對任意一個對象,都能調用它的任意一個方法和屬性。這種能動態獲取信息及動態調用對象方法的功能稱爲java語言的反射機制。

反射的作用:開發過程中,經常會遇到某個類的某個成員變量、方法或屬性是私有的,或只對系統應用開放,這裏就可以利用java的反射機制通過反射來獲取所需的私有成員或是方法。

1) 獲取類的Class對象實例 Class clz = Class.forName("com.zhenai.api.Apple");

2) 根據Class對象實例獲取Constructor對象  Constructor appConstructor = clz.getConstructor();

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

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

5) 利用invoke方法調用方法  setPriceMethod.invoke(appleObj, 14);

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

11、說說你對Java註解的理解

註解是通過@interface關鍵字來進行定義的,形式和接口差不多,只是前面多了一個@

public @interface TestAnnotation {
}

使用時@TestAnnotation來引用,要使註解能正常工作,還需要使用元註解,它是可以註解到註解上的註解。元標籤有@Retention @Documented @Target @Inherited @Repeatable五種

@Retention說明註解的存活時間,取值有RetentionPolicy.SOURCE註解只在源碼階段保留,在編譯器進行編譯時被丟棄;RetentionPolicy.CLASS 註解只保留到編譯進行的時候,並不會被加載到JVM中。RetentionPolicy.RUNTIME可以留到程序運行的時候,它會被加載進入到JVM中,所以在程序運行時可以獲取到它們。

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

@Target  限定註解的應用場景,ElementType.FIELD給屬性進行註解;ElementType.LOCAL_VARIABLE可以給局部變量進行註解;ElementType.METHOD可以給方法進行註解;ElementType.PACKAGE可以給一個包進行註解 ElementType.TYPE可以給一個類型進行註解,如類、接口、枚舉

@Inherited 若一個超類被@Inherited註解過的註解進行註解,它的子類沒有被任何註解應用的話,該子類就可繼承超類的註解;

註解的作用:

1)提供信息給編譯器:編譯器可利用註解來探測錯誤和警告信息

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

3)運行階段:程序運行時可利用註解提取代碼

註解是通過反射獲取的,可以通過Class對象的isAnnotationPresent()方法判斷它是否應用了某個註解,再通過getAnnotation()方法獲取Annotation對象

12、說一下泛型原理,並舉例說明

泛型就是將類型變成參數傳入,使得可以使用的類型多樣化,從而實現解耦。Java泛型是在Java1.5以後出現的,爲保持對以前版本的兼容,使用了擦除的方法實現泛型。擦除是指在一定程度無視類型參數T,直接從T所在的類開始向上T的父類去擦除,如調用泛型方法,傳入類型參數T進入方法內部,若沒在聲明時做類似public T methodName(T extends Father t){},Java就進行了向上類型的擦除,直接把參數t當做Object類來處理,而不是傳進去的T。

即在有泛型的任何類和方法內部,它都無法知道自己的泛型參數,擦除和轉型都是在邊界上發生,即傳進去的參在進入類或方法時被擦除掉,但傳出來的時候又被轉成了我們設置的T。在泛型類或方法內,任何涉及到具體類型(即擦除後的類型的子類)操作都不能進行,如new T(),或者T.play()(play爲某子類的方法而不是擦除後的類的方法)

13、Java中String的瞭解

1)String類是final型,固String類不能被繼承,它的成員方法也都默認爲final方法。String對象一旦創建就固定不變了,對String對象的任何改變都不影響到原對象,相關的任何改變操作都會生成新的String對象。

2)String類是通過char數組來保存字符串的,String對equals方法進行了重定,比較的是值相等。

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

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

例:

String str1 = "abc"; //棧中開闢一塊空間存放引用str1,str1指向池中String常量"abc"
String str2 = "def"; //棧中開闢一塊空間存放引用str2,str2指向池中String常量"def"
String str3 = str1 + str2;//棧中開闢一塊空間存放引用str3
//str1+str2通過StringBuilder的最後一步toString()方法返回一個新的String對象"abcdef"
//會在堆中開闢一塊空間存放此對象,引用str3指向堆中的(str1+str2)所返回的新String對象。
System.out.println(str3 == "abcdef");//返回false
因爲str3指向堆中的"abcdef"對象,而"abcdef"是字符池中的對象,所以結果爲false。JVM對String str="abc"對象放在常量池是在編譯時做的,而String str3=str1+str2是在運行時才知道的,new對象也是在運行時才做的。

14、String爲什麼要設計成不可變的?

1)字符串常量池需要String不可變
因爲String設計成不可變,當創建一個String對象時,若此字符串值已經存在於常量池中,則不會創建一個新的對象,而是引用已經存在的對象。如果字符串變量允許必變,會導致各種邏輯錯誤,如改變一個對象會影響到另一個獨立對象。

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

3)安全性。
String被許多java類用來當作參數,如url地址,文件path路徑,反射機制所需的Strign參數等,若String可變,將會引起各種安全隱患。                                                                    

(更多完整項目下載。未完待續。源碼。圖文知識後續上傳github。)
可以點擊關於我聯繫我獲取完整PDF
(VX:×××)

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章