Java后端面試題目及答案匯總


1、Java與C++的區別?

Java源碼會先經過編譯器編譯成字節碼(class文件),然后由JVM中內置的解釋器解釋成機器碼。而C++源碼直徑過一次編譯,直接在編譯的過程中鏈接了,形成機器碼

C++比Java執行效率快,但是Java可以利用JVM跨平台

Java是純面向對象的語言,所有代碼都必須在勒種定義。而C++中還有面向過程的東西,比如全局變量和全局函數

C++中有指針,Java中沒有,但是有引用

C++支持多繼承,Java類都是單繼承。但是繼承都有傳遞性,同時Java中的接口是多繼承,接口可以多實現

Java 中內存的分配和回收由Java虛擬機實現。Java 中有垃圾自動回收機制,會自動清理引用數為0的對象。而在 C++ 編程時,則需要花精力考慮如何避免內存泄漏。

C++運算符可以重載,但是Java中不可以。同時C++中支持強制自動轉型,Java中不行,會出現ClassCastException(類型不匹配)。

2、Java堆內存和棧內存的區別

Java把內存分成兩種,一種叫做棧內存,一種叫做堆內存。

在函數中定義的一些基本類型的變量和對象的引用變量都是在函數的棧內存中分配。當在一段代碼塊中定義一個變量時,java就在棧中為這個變量分配內存空間,當超過變量的作用域后,java會自動釋放掉為該變量分配的內存空間,該內存空間可以立刻被另作他用。

堆內存用於存放由new創建的對象和數組。在堆中分配的內存,由java虛擬機自動垃圾回收器來管理。在堆中產生了一個數組或者對象后,還可以在棧中定義一個特殊的變量,這個變量的取值等於數組或者對象在堆內存中的首地址,在棧中的這個特殊的變量就變成了數組或者對象的引用變量,以后就可以在程序中使用棧內存中的引用變量來訪問堆中的數組或者對象,引用變量相當於為數組或者對象起的一個別名,或者代號。

引用變量是普通變量,定義時在棧中分配內存,引用變量在程序運行到作用域外釋放。而數組&對象本身在堆中分配,即使程序運行到使用new產生數組和對象的語句所在地代碼塊之外,數組和對象本身占用的堆內存也不會被釋放,數組和對象在沒有引用變量指向它的時候,才變成垃圾,不能再被使用,但是仍然占着內存,在隨后的一個不確定的時間被垃圾回收器釋放掉。這個也是java比較占內存的主要原因,實際上,棧中的變量指向堆內存中的變量,這就是 Java 中的指針!

3、Java的垃圾回收機制,什么時候會出現Full GC

由於Java有垃圾回收機制,Java中的對象不再有“作用域”的概念,只有對象的引用才有“作用域”。垃圾回收可以有效的防止內存泄露,有效的使用空閑的內存。

ps:內存泄露是指該內存空間使用完畢之后未回收

什么情況下回導致內存泄漏?

1.靜態集合類像HashMap、Vector等的使用最容易出現內存泄露,這些靜態變量的生命周期和應用程序一致,所有的對象Object也不能被釋放,因為他們也將一直被Vector等應用着。

2.各種連接,數據庫連接,網絡連接,IO連接等沒有顯示調用close關閉,不被GC回收導致內存泄露。

3.監聽器的使用,在釋放對象的同時沒有相應刪除監聽器的時候也可能導致內存泄露。

 

Java分代的垃圾回收策略,是基於這樣一個事實:不同的對象的生命周期是不一樣的。因此,不同生命周期的對象可以采取不同的回收算法,以便提高回收效率。

分為三代:

①年輕代。

1.所有新生成的對象首先都是放在年輕代的。年輕代的目標就是盡可能快速的收集掉那些生命周期短的對象。

2.新生代內存按照8:1:1的比例分為一個eden區和兩個survivor(survivor0,survivor1)區。一個Eden區,兩個 Survivor區(一般而言)。大部分對象在Eden區中生成。回收時先將eden區存活對象復制到一個survivor0區,然后清空eden區,當這個survivor0區也存放滿了時,則將eden區和survivor0區存活對象復制到另一個survivor1區,然后清空eden和這個survivor0區,此時survivor0區是空的,然后將survivor0區和survivor1區交換,即保持survivor1區為空, 如此往復。

3.當survivor1區不足以存放 eden和survivor0的存活對象時,就將存活對象直接存放到老年代。若是老年代也滿了就會觸發一次Full GC,也就是新生代、老年代都進行回收

4.新生代發生的GC也叫做Minor GC,MinorGC發生頻率比較高(不一定等Eden區滿了才觸發)

②年老代。

1.在年輕代中經歷了N次垃圾回收后仍然存活的對象,就會被放到年老代中。因此,可以認為年老代中存放的都是一些生命周期較長的對象。

2.內存比新生代也大很多(大概比例是1:2),當老年代內存滿時觸發Major GC即Full GC,Full GC發生頻率比較低,老年代對象存活時間比較長,存活率標記高。

③持久代

用於存放靜態文件,如Java類、方法等。持久代對垃圾回收沒有顯著影響,但是有些應用可能動態生成或者調用一些class,例如Hibernate 等,在這種時候需要設置一個比較大的持久代空間來存放這些運行過程中新增的類。

 

不同的收集器采用的算法不一樣,如復制算法,標記-整理算法,標記-復制算法,停止-復制算法。

新生代收集器使用的收集器:Serial(復制算法)、PraNew(停止-復制算法)、Parallel Scavenge(停止-復制算法)

老年代收集器使用的收集器:Serial Old(標記-整理算法)、Parallel Old(停止-復制算法)、CMS(標記-清理算法)。

 

由於對象進行了分代處理,因此垃圾回收區域、時間也不一樣。

GC有兩種類型:Scavenge GC和Full GC。

Scavenge GC

    一般情況下,當新對象生成,並且在Eden申請空間失敗時,就會觸發Scavenge GC,對Eden區域進行GC,清除非存活對象,並且把尚且存活的對象移動到Survivor區。然后整理Survivor的兩個區。這種方式的GC是對年輕代的Eden區進行,不會影響到年老代。因為大部分對象都是從Eden區開始的,同時Eden區不會分配的很大,所以Eden區的GC會頻繁進行。因而,一般在這里需要使用速度快、效率高的算法,使Eden去能盡快空閑出來。

Full GC

    對整個堆進行整理,包括Young、Tenured和Perm。Full GC因為需要對整個堆進行回收,所以比Scavenge GC要慢,因此應該盡可能減少Full GC的次數。在對JVM調優的過程中,很大一部分工作就是對於FullGC的調節。

有如下原因可能導致Full GC:

  1.年老代(Tenured)被寫滿

  2.持久代(Perm)被寫滿 

  3.System.gc()被顯示調用 

  4.上一次GC之后Heap的各域分配策略動態變化

【參考】https://www.cnblogs.com/sunniest/p/4575144.html

 4、Java容器都有哪些?

Java 容器分為 Collection 和 Map 兩大類。具體的分類如下:

Collection

  List(有序,可重復)    

    ArrayList,底層用Object數組實現,特點是查詢效率高,增刪效率低,線程不安全, 初始化長度是10,默認是16,通過定義更大的數組,將舊數組中的值復制到新數組實現擴容 newC = 1.5oldC +1
    LinkedList,底層使用雙向循環鏈表實現,特點是查詢效率低,增刪效率高,線程不安全,因為線程不同步
    Vector,底層用長度可以動態增長的對象數組實現,它的相關方法用 Synchronized 進行了線程同步,所以線程安全,效率低
      Stack,棧。特點是:先進后出(FILO, First In Last Out)。繼承於Vector
  Set 無序,不可重復
    HashSet,底層用HashMap實現,本質是一個簡化版的HashMap,因此查詢效率和增刪效率都比較高。其add方法就是在map中增加一個鍵值對,鍵對象就是這個元素,值對象是PRESENT的對象
      LinkedHashSet,LinkedHashSet繼承自HashSet,內部使用的是LinkHashMap。這樣做的意義或者好處就是LinkedHashSet中的元素順序是可以保證的,也就是說遍歷序和插入序是一致的。
    TreeSet,底層用TreeMap實現,底層是一種二叉查找樹(紅黑樹),需要對元素做內部排序。內部維持了一個簡化版的TreeMap,並通過key來存儲Set元素。使用時,要對放入的類實現                                 Comparable接口,且不能放入null
Map
  HashMap,采用散列算法來實現,底層用哈希表來存儲數據,因此要求鍵不能重復。線程不安全,HashMap在查找、刪除、修改方面效率都非常高。允許key或value為null

                        哈希表:本質是“數組+鏈表”,源碼中Entery[] table是HashMap的核心數組結構,稱為“位桶數組”。其中Entery對象時一個單向鏈表,存儲了四部分(hash值,key,value,next)內容。

            早期的hash值總是1,此時,每一個對象都會存儲到索引為1的位置,每存儲一個都會發生hash沖突,形成了一個非常長的鏈表,HashMap也就退化成了一個“鏈表”。

           如果利用相除取余算法,能使hash值均勻地分布在[0,數組長度-1]區間內,早期的HashTable就是采用這種算法,但由於用了除法,所以效率非常低。

            JDK后來改進了算法,首先約定數組的長度必須為2的整數冪,這樣可以使用位運算實現取余效果,hash值 = hashcode & (數組長度-1)。而且為了獲得更好的散列效果,JDK對                                         hashcode進行了兩次散列處理,目標就是為了使分布的更散列,更均勻。

            擴容問題:hashMap 的位桶數組,初始大小為16.負載因子為0.75,每次擴容2倍。需要注意的是,擴容很耗時。因為擴容的本質是定義更大的數組,並將就數組中的內容逐個復制                                                    到新數組中。在JDK8中,HashMap在存儲一個元素時,當對應鏈表長度大於8時,鏈表就轉化為紅黑樹,這樣就大大提高了查詢效率

                               

    LinkedHashMap,HashMap和雙向鏈表合二為一即是LinkedHashMap。所謂LinkedHashMap,其落腳點在HashMap,因此更准確地說,它是一個將所有Entry節點鏈入一個雙向鏈表的HashMap。雖然LinkedHashMap增加了時間和空間上的開銷,但是它通過維護一個額外的雙向鏈表保證了迭代順序。特別地,該迭代順序可以是插入順序,也可以是訪問順序。因此,根據鏈表中元素的順序可以將LinkedHashMap分為:保持插入順序的LinkedHashMap 和 保持訪問順序的LinkedHashMap,其中LinkedHashMap的默認實現是按插入順序排序的。

  HashTable,與HashMap類似,只是其中的方法添加了synchronized關鍵字以確保線程同步檢查,線程安全,但效率較低。不允許key或value為null
  TreeMap,紅黑樹的典型實現。TreeMap和HashMap實現了同樣的接口Map。在需要Map中Key按照自然排序時才選用TreeMap

  ConcurrentHashMap, 它在JDK1.7和1.8中略有差別

JDK1.7中:

由於JDK沒有對HashMap做任何的同步操作,所以並發會出問題,甚至出現死循環導致系統不可用。因此 JDK 推出了專項專用的 ConcurrentHashMap ,該類位於 java.util.concurrent 包下,專門用於解決並發問題。和 HashMap 非常類似,唯一的區別就是其中的核心數據如 value ,以及鏈表都是 volatile 修飾的,保證了獲取時的可見性。

原理上來說:ConcurrentHashMap 采用了分段鎖技術,其中 Segment 繼承於 ReentrantLock。不會像 HashTable 那樣不管是 put 還是 get 操作都需要做同步處理,理論上 ConcurrentHashMap 支持 CurrencyLevel (Segment 數組數量)的線程並發。每當一個線程占用鎖訪問一個 Segment 時,不會影響到其他的 Segment。

由於 HashEntry 中的 value 屬性是用 volatile 關鍵詞修飾的,保證了內存可見性,所以每次獲取時都是最新值。

ConcurrentHashMap 的 get 方法是非常高效的,因為整個過程都不需要加鎖。

JDK1.8中:

1.7 已經解決了並發問題,並且能支持 N 個 Segment 這么多次數的並發,但依然存在 HashMap 在 1.7 版本中的問題。

那就是查詢遍歷鏈表效率太低

其中拋棄了原有的 Segment 分段鎖,而采用了 CAS + synchronized 來保證並發安全性。

其中,CAS是英文單詞Compare And Swap的縮寫,翻譯過來就是比較並替換。

【CAS機制當中使用了3個基本操作數:內存地址V,舊的預期值A,要修改的新值B。更新一個變量的時候,只有當變量的預期值A和內存地址V當中的實際值相同時,才會將內存地址V對應的值修改為B。從思想上來說,Synchronized屬於悲觀鎖,悲觀地認為程序中的並發情況嚴重,所以嚴防死守。CAS屬於樂觀鎖,樂觀地認為程序中的並發情況不那么嚴重,所以讓線程不斷去嘗試更新。】

1.8 在 1.7 的數據結構上做了大的改動,采用紅黑樹之后可以保證查詢效率(O(logn)),甚至取消了 ReentrantLock 改為了 synchronized,這樣可以看出在新版的 JDK 中對 synchronized 優化是很到位的。

更多請參考:https://blog.csdn.net/weixin_44460333/article/details/86770169


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM