今天帶大家分析一下java深刻源碼級的面試題

今天雙11剁手節,祝你們節日快樂html

今天和你們一塊兒分析一下那些面試中可能會問到的java深刻源碼級的面試題java

對此不少面試中遇到的問題,花了15個小時整理成爲了一份983頁的PDF文檔。

git

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

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

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

1.1 哪些對象能夠被看作是GC Roots呢?

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

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

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

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

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

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

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

編碼的意義:計算機中存儲的最小單元是一個字節即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個字節組成。                   

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

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

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

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

區別:

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

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

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

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

五、Java的異常體系

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

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

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

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

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

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

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

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

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

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

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

九、如何將一個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();
}

十、說說你對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`也是如此。

十一、說說你對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對象

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

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

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

1三、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對象也是在運行時才作的。

1四、String爲何要設計成不可變的?

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

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

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

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

相關文章
相關標籤/搜索