【Java基礎知識面試題 1】2020年6月19日  星期五

2020年6月18日  星期四

1、單例模式

(1)單例模式定義

小白:

單例模式是保證一個類只有一個實例,保證線程安全。

答案:

單例模式確保某個類只有一個實例,而且自行實例化並向整個系統提供這個實例。在計算機系統中,線程池、緩存、日誌對象、對話框、打印機、顯卡 的驅動程序對象常被設計成單例。這些應用都或多或少具有資源管理器的功能。每臺計算機可以有若干個打印機,但只能有一個 Printer Spooler,以避免 兩個打印作業同時輸出到打印機中。每臺計算機可以有若干通信端口,系統應當集中管理這些通信端口,以避免一個通信端口同時被兩個請求同時調用。 總之,選擇單例模式就是爲了避免不一致狀態。

(2)單例模式特點

小白:

保證一個類只有一個實例,保證線程安全。

答案:

  1. 單例類只能有一個實例。
  2. 單例類必須自己創建自己的唯一實例。
  3. 單例類必須給所有其他對象提供這一實例。
  4. 單例模式保證了全局對象的唯一性,比如系統啓動讀取配置文件就需要單例保證配置的一致性。

(3)單例模式的四大原則

小白:唯一性,靜態單例。

答案:

  1. 構造私有;
  2. 以靜態方法或者枚舉返回實例 ;
  3. 確保實例只有一個,尤其是多線程環境 ;
  4. 確保反序列換時不會重新構建對象。

(4)實現單例模式的方式

小白:

餓漢式、懶漢式、靜態內部類、雙重檢索、枚舉。

答案:

(1)餓漢式(立即加載);

(2)懶漢式(延遲加載);

(3)同步鎖(解決線程安全問題):

(4)雙重檢查鎖(提高同步鎖的效率);

(5) 靜態內部類;

(6)內部枚舉類實現(防止反射攻擊);

2、你是怎樣理解面向對象的

小白:

面向對象三大特點

封裝、繼承、多態、

答案:

面向對象是利於語言對現實事物進行抽象。面向對象具有以下四大特徵:

(1)繼承:繼承是從已有類得到繼承信息創建新類的過程 ;

(2)封裝:通常認爲封裝是把數據和操作數據的方法綁定起來,對數據的訪問只能通過已定義的接口;

(3)多態性:多態性是指允許不同子類型的對象對同一消息作出不同的響應;

(4)抽象:抽象是將一類對象的共同特徵總結出來構造類的過程,包括數據抽象和行爲抽象兩方面。

3、int和Integer有什麼區別

(1)int是基本數據類型,Integer是int的封裝類型;

(2)int可以沒有初始值,Integer必須設置初始值;

(3)int默認爲0,Integer默認爲null;

4、==和equals的區別

==

(1)在基本類型比較時,比較的是數值;

(2)在封裝類型比較時,比較的是地址值;

equals

(1)沒重寫equals方法時,比較的是地址值,因爲equals在object類中的實現就是==;

(2)重寫equals方法後,比較的是對象中的屬性值;

5、談談你對反射的理解

(1)反射機制

小白:

反射機制是通過getClass方法獲取java類自身的一些屬性,比如類名、變量、方法等。

答案:

所謂的反射機制就是 java 語言在運行時擁有一項自觀的能力。通過這種能力可以徹底的瞭解自身的情況爲下一步的動作做準備。 Java 的反射機制的實現要藉助於 4 個類:class,Constructor,Field,Method; 其中 class 代表的時類對 象,Constructor-類的構造器對象,Field-類的屬性對象,Method-類的方法對象。通過這四個對象我們可以粗略的看到一個 類的各個組 成部分。

(2)Java反射的作用

小白:

獲取這個類的屬性,比如類名、變量、方法、參數等。

答案:

在 Java 運行時環境中,對於任意一個類,可以知道這個類有哪些屬性和方法。對於任意一個對象,可以調用它的任意一個方法。這種動態獲取類的信息 以及動態調用對象的方法的功能來自於 Java 語言的反射(Reflection)機制。

(3)Java反射機制提供功能

  • 在運行時判斷任意一個對象所屬的類;
  • 在運行時構造任意一個類的對象;
  • 在運行時判斷任意一個類所具有的成員變量和方法;
  • 在運行時調用任意一個對象的方法;

6、ArrayList和LinkedList區別

小白:

(1)ArrayList的底層實現是數組,linkedlist的底層實現是鏈表;

(2)ArrayList的插入和更新更快,LinkedList的添加和刪除更快,因爲這也是數組和鏈表的區別;

答案:

(1)ArrayList 是實現了基於動態數組的數據結構,LinkedList 基於鏈表的數據結構。

(2)對於隨機訪問 get 和 set,ArrayList 覺得優於 LinkedList,因爲 LinkedList 要移動指針。

(3)對於新增和刪除操作 add 和 remove,LinkedList 比較佔優勢,因爲 ArrayList 要移動數據。 這一點要看實際情況的。若只對單條數據插入或刪除, ArrayList 的速度反而優於 LinkedList。但若是批量隨機的插入刪除數據,LinkedList 的速度大大優於 ArrayList. 因爲 ArrayList 每插入一條數據,要移動 插入點及之後的所有數據。

7、HashMap底層源碼

1.7之前是數組+鏈表的形式;

1.8開始是數組+鏈表+紅黑樹的形式;

8、HashMap和HashTable的區別

小白:

(1)HashMap線程不安全,HashTable線程安全,HashTable內部包含synchronized,HashMap要想線程安全,可以使用一些同步方法。

(2)HashMap的key和value允許爲null,HashTable的key和value都不可以爲null;

答案:

(1)線程安全性不同 HashMap 是線程不安全的,HashTable 是線程安全的,其中的方法是 Synchronize 的,在多線程併發的情況下,可以直接使用 HashTabl,但是使用 HashMap 時必須自己增加同步處理。

(2)是否提供 contains 方法 HashMap 只有 containsValue 和 containsKey 方法;HashTable 有 contains、containsKey 和 containsValue 三個方法,其中 contains 和 containsValue 方法功能 相同。

(3)key 和 value 是否允許 null 值 Hashtable 中,key 和 value 都不允許出現 null 值。HashMap 中,null 可以作爲鍵,這樣的鍵只有一個;可以有一個或多個鍵所對應的值爲 null。

(4)數組初始化和擴容機制 HashTable 在不指定容量的情況下的默認容量爲 11,而 HashMap 爲 16,Hashtable 不要求底層數組的容量一定要爲 2 的整數次冪,而 HashMap 則要求一 定爲 2 的整數次冪。 Hashtable 擴容時,將容量變爲原來的 2 倍加 1,而 HashMap 擴容時,將容量變爲原來的 2 倍。

9、TreeSet和HashSet的區別

小白:

set是沒有重複的元素;

TreeSet是有序的set;

HashSet是無序的Set;

答案:

HashSet 是採用 hash 表來實現的。其中的元素沒有按順序排列,add()、remove()以及 contains()等方法都是複雜度爲 O(1)的方法。

TreeSet 是採用樹結構實現(紅黑樹算法)。元素是按順序進行排列,但是 add()、remove()以及 contains()等方法都是複雜度爲 O(log (n))的方法。它還提供 了一些方法來處理排序的 set,如 first(), last(), headSet(), tailSet()等等。

10、StringBuffer和StringBuilder的區別

小白:

stringbuffer是線程安全的,stringbuilder是線程不安全的,stringbuilder速度比stringbuffer要快,因爲沒有同步方法;

答案:

(1)StringBuffer 與 StringBuilder 中的方法和功能完全是等價的;

(2)只是 StringBuffer 中的方法大都採用了 synchronized 關鍵字進行修飾,因此是線程安全的,而 StringBuilder 沒有這個修飾,可以被認爲是線程不 安全的;

(3)在單線程程序下,StringBuilder 效率更快,因爲它不需要加鎖,不具備多線程安全而 StringBuffer 則每次都需要判斷鎖,效率相對更低

11、Final、Finally、Finalize區別

(1)final可以修飾類、變量、方法

修飾類時,這個類不能被繼承。

修飾變量時,這個變量必須賦值,在引用中只能讀取不可修改,即爲常量;

修飾方法時,這個方法不能被子類重寫;

(2)finally:通常放在 try…catch 的後面構造最終執行代碼塊,這就意味着程序無論正常執行還是發生異常,這裏的代碼只要 JVM 不關閉都能執行,可以將 釋放外部資源的代碼寫在 finally 塊中。

(3)finalize() Object 類中定義的方法,Java 中允許使用 finalize() 方法在垃圾收集器將對象從內存中清除出去之前做必要的清理工作。這個方法是由垃圾收集 器在銷燬對象時調用的,通過重寫 finalize() 方法可以整理系統資源或者執行其他清理工作。

12、什麼是Java序列化,如何實現Java序列化

小白:Java序列化是通過IO流的形式將對象存儲在內存中,再通過反序列化將內存中的對象轉爲java對象,有助於對象的傳輸,實現serializable接口即可實現序列化,transient或static修飾的變量不會被序列化和反序列化。

答案:

序列化就是一種用來處理對象流的機制,所謂對象流就是將對象的內容進行流化。可以對流化後的對象進行讀寫操作,也可以將流化後的對象傳輸於網絡之間,

序列化的實現:

  • 實現serializable接口,該接口沒有需要實現的方法;然後使用一個輸出流(FileOutputStream)來構造一個ObjectOutputStream(對象流)對象,然後使用writeObject(Obejct obj)方法就可以將obj寫出(即保存其狀態),要恢復的話則用輸入流。

13、Object中有哪些方法

  • getcode()
  • getClass()
  • toString()
  • equals()
  • finalize()
  • wait()
  • notify()
  • notifyAll()
  • clone()

14、線程由幾種狀態,產生的條件是什麼

小白:

(1)創建狀態:Thread thread = new Thread();

(2)就緒狀態:調用start()後;

(3)執行狀態:

(4)阻塞狀態:

造成阻塞狀態的三種原因:

  • 等待阻塞
  • 線程阻塞
  • sleep造成的阻塞

(5)死亡狀態

答案:

(1)創建狀態:Thread thread = new Thread();

(2)就緒狀態:調用start()後;

(3)執行狀態:只能從就緒狀態進入執行狀態;

(4)阻塞狀態:阻塞狀態是線程因爲某種原因放棄CPU使用權,暫時停止運行,直到線程進入就緒狀態,纔會有機會轉到運行狀態。

造成阻塞狀態的三種原因:

  • 等待阻塞:通過調用線程的wait()方法,讓線程等待某工作的完成。
  • 線程阻塞:線程獲取synchronized同步鎖失敗(因爲鎖被其它線程鎖佔用),它會進入同步阻塞狀態;
  • 其它阻塞:通過調用線程的sleep()或join()或發出了IO請求時,線程就會進入阻塞狀態。當sleep()超時、join()等待線程終止或超時、或者IO處理完畢時,線程重新轉入就緒狀態。

(5)死亡狀態:線程執行完了或者因異常退出了 run()方法,該線程結束生命週期。

15、產生死鎖的基本條件

(1)產生死鎖的原因

小白:不會

答案:

  • 因爲系統資源不足;
  • 進程運行推進的順序不合適;
  • 資源分配不當;

如果系統資源充足,進程的資源請求都能得到滿足,死鎖出現的可能性就會很低,否者就會因爲爭奪有限的資源而陷入死鎖。其次,進程運行推進順序與速度不同,也可能產生死鎖。

(2)產生死鎖的四個必要條件

小白:

  • 互斥條件
  • 請求和保持條件
  • 不剝奪條件
  • 環路等待條件

答案:

① 互斥條件:指進程對所分配到的資源進行排它性使用,在一段時間內某資源只由一個進程佔用,如果此時還有其他進程請求資源,則請求者只能等待,直至佔有資源的進程被釋放。

② 請求和保持條件:指進程已經保持至少一個資源,但又提出了新的資源請求,而該資源已被其它進程佔有,此時請求進程阻塞,但又對自己已獲得的其它資源保持不放。

③ 不剝奪條件:指進程已獲得的資源,在未使用完之前,不能被剝奪,只能在使用完時由自己釋放。

④環路等待條件:在發生死鎖時,必然存在一個進程,資源的喚醒鏈,即進程集合{P0,P1,P2,···,Pn}中的P0正在等待一個P1佔用的資源;P1正在等待P2佔用的資源,……,Pn正在等待已被P0佔用的資源。

(3)死鎖的解除和預防

小白:

強制解鎖;

答案:

如何不讓四個條件成立,如何確定資源的合理分配,避免進程永久佔據系統資源;

也要防止進程在處於等待狀態的情況下佔用資源。

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