1. 程式人生 > >BAT大企Java技術面試精選

BAT大企Java技術面試精選

原文:https://blog.csdn.net/hang1995/article/details/79163350 

JVM的類載入機制是什麼?有哪些實現方式?
類載入機制:

類的載入指的是將類的.class檔案中的二進位制資料讀入到記憶體中,將其放在執行時資料區的方法去內,然後在堆區建立一個java.lang.Class物件,用來封裝在方法區內的資料結構。類的載入最終是在堆區內的Class物件,Class物件封裝了類在方法區內的資料結構,並且向Java程式設計師提供了訪問方法區內的資料結構的介面。

如果你也想在IT行業拿高薪,可以參加我們的訓練營課程,選擇最適合自己的課程學習,技術大牛親授,7個月後,進入名企拿高薪。我們的課程內容有:Java工程化、高效能及分散式、高效能、深入淺出。高架構。效能調優、Spring,MyBatis,Netty原始碼分析和大資料等多個知識點。如果你想拿高薪的,想學習的,想就業前景好的,想跟別人競爭能取得優勢的,想進阿里面試但擔心面試不過的,你都可以來,群號為:697579751

類載入有三種方式:

1)命令列啟動應用時候由JVM初始化載入

2)通過Class.forName()方法動態載入

3)通過ClassLoader.loadClass()方法動態載入

JVM的常見垃圾回收演算法?
1)標記-清楚演算法:前後線標記處所有需要回收的物件,在標記完成後統一回收有被標記的物件。

2)複製演算法:將可用記憶體按容量劃分為大小相等的兩塊,每次只使用其中的一塊。當一塊記憶體用完了,將其存在另外一塊上面,然後再把已使用過的記憶體空間一次清理掉。

3)標記-整理演算法:標記過程與“標記-清除”演算法一樣,但後續步驟不是直接對可回收物件進行清理,而是讓所一端移動,然後直接清理掉端邊界以外的記憶體。

4)分代收集演算法:一般是把Java堆分為新生代和老年代,根據各個年代的特點採用最適當的收集演算法。新生代都發現有大批物件死去,選用複製演算法。老年代中因為物件存活率高,必須使用“標記-清理”或“標記-整理”演算法來進行回收。

JVM調優的常見命令列工具有哪些?JVM常見的調優引數有哪些?
(1)JVM調優的常見命令工具包括:

1)jps命令用於查詢正在執行的JVM程序,

2)jstat可以實時顯示本地或遠端JVM程序中類裝載、記憶體、垃圾收集、JIT編譯等資料

3)jinfo用於查詢當前執行這的JVM屬性和引數的值。

4)jmap用於顯示當前Java堆和永久代的詳細資訊

5)jhat用於分析使用jmap生成的dump檔案,是JDK自帶的工具

6)jstack用於生成當前JVM的所有執行緒快照,執行緒快照是虛擬機器每一條執行緒正在執行的方法,目的是定位執行緒出現長時間停頓的原因。

(2)JVM常見的調優引數包括:

-Xmx

  指定java程式的最大堆記憶體, 使用java -Xmx5000M -version判斷當前系統能分配的最大堆記憶體

-Xms

  指定最小堆記憶體, 通常設定成跟最大堆記憶體一樣,減少GC

-Xmn

  設定年輕代大小。整個堆大小=年輕代大小 + 年老代大小。所以增大年輕代後,將會減小年老代大小。此值對系統性能影響較大,Sun官方推薦配置為整個堆的3/8。

-Xss

  指定執行緒的最大棧空間, 此引數決定了java函式呼叫的深度, 值越大呼叫深度越深, 若值太小則容易出棧溢位錯誤(StackOverflowError)

-XX:PermSize

  指定方法區(永久區)的初始值,預設是實體記憶體的1/64, 在Java8永久區移除, 代之的是元資料區, 由-XX:MetaspaceSize指定

-XX:MaxPermSize

  指定方法區的最大值, 預設是實體記憶體的1/4, 在java8中由-XX:MaxMetaspaceSize指定元資料區的大小

-XX:NewRatio=n

  年老代與年輕代的比值,-XX:NewRatio=2, 表示年老代與年輕代的比值為2:1

-XX:SurvivorRatio=n

  Eden區與Survivor區的大小比值,-XX:SurvivorRatio=8表示Eden區與Survivor區的大小比值是8:1:1,因為Survivor區有兩個(from, to)

ConcurrentHashMap加鎖機制是什麼,詳細說一下?
HashTable容器在競爭激烈的併發環境下表現出效率低下的原因,是因為所有訪問HashTable的執行緒都必須競爭同一把鎖,那假如容器裡有多把鎖,每一把鎖用於鎖容器其中一部分資料,那麼當多執行緒訪問容器裡不同資料段的資料時,執行緒間就不會存在鎖競爭,從而可以有效的提高併發訪問效率,這就是ConcurrentHashMap所使用的鎖分段技術,首先將資料分成一段一段的儲存,然後給每一段資料配一把鎖,當一個執行緒佔用鎖訪問其中一個段資料的時候,其他段的資料也能被其他執行緒訪問。

G1收集器簡介?以及它的記憶體劃分怎麼樣的?
(1)簡介:

Garbage-First(G1,垃圾優先)收集器是服務型別的收集器,目標是多處理器機器、大記憶體機器。它高度符合垃圾收集暫停時間的目標,同時實現高吞吐量。Oracle JDK 7 update 4 以及更新發布版完全支援G1垃圾收集器

(2)G1的記憶體劃分方式:

它是將堆記憶體被劃分為多個大小相等的 heap 區,每個heap區都是邏輯上連續的一段記憶體(virtual memory). 其中一部分割槽域被當成老一代收集器相同的角色(eden, survivor, old), 但每個角色的區域個數都不是固定的。這在記憶體使用上提供了更多的靈活性

在重寫equals方法時,需要遵循哪些約定,具體介紹一下?
重寫equals方法時需要遵循通用約定:自反性、對稱性、傳遞性、一致性.、非空性

1)自反性

對於任何非null的引用值x,x.equals(x)必須返回true。---這一點基本上不會有啥問題

2)對稱性

對於任何非null的引用值x和y,當且僅當x.equals(y)為true時,y.equals(x)也為true。

3)傳遞性

對於任何非null的引用值x、y、z。如果x.equals(y)==true,y.equals(z)==true,那麼x.equals(z)==true。

4) 一致性

對於任何非null的引用值x和y,只要equals的比較操作在物件所用的資訊沒有被修改,那麼多次呼叫x.eqals(y)就會一致性地返回true,或者一致性的返回false。

5)非空性

所有比較的物件都不能為空。

Synchronized優化後的鎖機制簡單介紹一下,包括自旋鎖、偏向鎖、輕量級鎖、重量級鎖?
自旋鎖:

執行緒自旋說白了就是讓cup在做無用功,比如:可以執行幾次for迴圈,可以執行幾條空的彙編指令,目的是佔著CPU不放,等待獲取鎖的機會。如果旋的時間過長會影響整體效能,時間過短又達不到延遲阻塞的目的。

偏向鎖

偏向鎖就是一旦執行緒第一次獲得了監視物件,之後讓監視物件“偏向”這個執行緒,之後的多次呼叫則可以避免CAS操作,

說白了就是置個變數,如果發現為true則無需再走各種加鎖/解鎖流程。

輕量級鎖:

輕量級鎖是由偏向所升級來的,偏向鎖執行在一個執行緒進入同步塊的情況下,當第二個執行緒加入鎖爭用的時候,偏向鎖就會升級為輕量級鎖;

重量級鎖

重量鎖在JVM中又叫物件監視器(Monitor),它很像C中的Mutex,除了具備Mutex(0|1)互斥的功能,它還負責實現了Semaphore(訊號量)的功能,也就是說它至少包含一個競爭鎖的佇列,和一個訊號阻塞佇列(wait佇列),前者負責做互斥,後一個用於做執行緒同步。

偏向鎖、輕量級鎖、重量級鎖的對比:

Redis和Memcache區別對比?如何選擇這兩個技術?
區別:

1) Redis和Memcache都是將資料存放在記憶體中,都是記憶體資料庫。不過memcache還可用於快取其他東西,例如圖片、視訊等等。

2)Redis不僅僅支援簡單的k/v型別的資料,同時還提供list,set,hash等資料結構的儲存。

3)虛擬記憶體--Redis當實體記憶體用完時,可以將一些很久沒用到的value 交換到磁碟

4)過期策略--memcache在set時就指定,例如set key1 0 0 8,即永不過期。Redis可以通過例如expire 設定,例如expire name 10

5)分散式--設定memcache叢集,利用magent做一主多從;redis可以做一主多從。都可以一主一從

6)儲存資料安全--memcache掛掉後,資料沒了;redis可以定期儲存到磁碟(持久化)

7)災難恢復--memcache掛掉後,資料不可恢復; redis資料丟失後可以通過aof恢復

8)Redis支援資料的備份,即master-slave模式的資料備份。

選型:

若是簡單的存取key-value這樣的資料用memcache好一些

若是要支援資料持久化,多資料型別(如集合、雜湊之類的),用列表型別做佇列之類的高階應用,就用redis

Redis的持久化機制是什麼?各自的優缺點?
redis提供兩種持久化機制RDB和AOF機制。

1)RDB持久化方式:

是指用資料集快照的方式記錄redis資料庫的所有鍵值對。

優點:

  1.只有一個檔案dump.rdb,方便持久化。

  2.容災性好,一個檔案可以儲存到安全的磁碟。

  3.效能最大化,fork子程序來完成寫操作,讓主程序繼續處理命令,所以是IO最大化。

  4.相對於資料集大時,比AOF的啟動效率更高。

缺點:

  1.資料安全性低。

2)AOF持久化方式:

是指所有的命令列記錄以redis命令請求協議的格式儲存為aof檔案。

優點:

  1.資料安全,aof持久化可以配置appendfsync屬性,有always,每進行一次命令操作就記錄到aof檔案中一次。

  2.通過append模式寫檔案,即使中途伺服器宕機,可以通過redis-check-aof工具解決資料一致性問題。

  3.AOF機制的rewrite模式。

缺點:

  1.檔案會比RDB形式的檔案大。

  2.資料集大的時候,比rdb啟動效率低。

Mysql的資料庫表鎖、行鎖、頁級鎖?
表鎖,直接鎖定整張表,在你鎖定期間,其它程序無法對該表進行寫操作。如果你是寫鎖,則其它程序則讀也不允許

行鎖,,僅對指定的記錄進行加鎖,這樣其它程序還是可以對同一個表中的其它記錄進行操作。

頁鎖,表級鎖速度快,但衝突多,行級衝突少,但速度慢。所以取了折衷的頁級,一次鎖定相鄰的一組記錄。

資料庫的四大特徵,資料庫的隔離級別?
資料庫的四大特徵:

(1)原子性(Atomicity)

原子性是指事務包含的所有操作要麼全部成功,要麼全部失敗回滾。

(2)一致性(Consistency)

一個事務執行之前和執行之後都必須處於一致性狀態。

(3)隔離性(Isolation)

隔離性是當多個使用者併發訪問資料庫時,比如操作同一張表時,資料庫為每一個使用者開啟的事務,不能被其他事務的操作所幹擾,多個併發事務之間要相互隔離。

4)永續性(Durability)

永續性是指一個事務一旦被提交了,那麼對資料庫中的資料的改變就是永久性的。

 資料庫的隔離級別:

1)Serializable (序列化):可避免髒讀、不可重複讀、幻讀的發生。2)Repeatable read (可重複讀):可避免髒讀、不可重複讀的發生。3)Read committed (讀已提交):可避免髒讀的發生。4)Read uncommitted (讀未提交):最低級別,任何情況都無法保證。

set集合從原理上如何保證不重複

1)在往set中新增元素時,如果指定元素不存在,則新增成功。也就是說,如果set中不存在(e==null ? e1==null : e.queals(e1))的元素e1,則e1能新增到set中。

2)具體來講:當向HashSet中新增元素的時候,首先計算元素的hashcode值,然後用這個(元素的hashcode)%(HashMap集合的大小)+1計算出這個元素的儲存位置,如果這個位置位空,就將元素新增進去;如果不為空,則用equals方法比較元素是否相等,相等就不新增,否則找一個空位新增。

HashMap和HashTable的主要區別是什麼?,兩者底層實現的資料結構是什麼?
HashMap和HashTable的區別:

二者都實現了Map 介面,是將惟一鍵對映到特定的值上;主要區別在於:

1)HashMap 沒有排序,允許一個null 鍵和多個null 值,而Hashtable 不允許;

2)HashMap 把Hashtable 的contains 方法去掉了,改成containsvalue 和

containsKey,因為contains 方法容易讓人引起誤解;

3)Hashtable 繼承自Dictionary 類,HashMap 是Java1.2 引進的Map 介面的實現;

4)Hashtable 的方法是Synchronize 的,而HashMap 不是,在多個執行緒訪問Hashtable 時,不需要自己為它的方法實現同步,而HashMap 就必須為之提供外同步。Hashtable 和HashMap 採用的hash/rehash 演算法大致一樣,所以效能不會有很大的差異。

HashMap和HashTable的底層實現資料結構:

HashMap和Hashtable的底層實現都是陣列+連結串列結構實現的

HashMap何時擴容,擴容的演算法是什麼?
HashMap何時擴容:

當向容器新增元素的時候,會判斷當前容器的元素個數,如果大於等於閾值---即當前陣列的長度乘以載入因子的值的時候,就要自動擴容

擴容的演算法是什麼:

擴容(resize)就是重新計算容量,向HashMap物件裡不停的新增元素,而HashMap物件內部的陣列無法裝載更多的元素時,物件就需要擴大陣列的長度,以便能裝入更多的元素。當然Java裡的陣列是無法自動擴容的,方法是使用一個新的陣列代替已有的容量小的陣列

Java的虛擬機器JVM的兩個記憶體:棧記憶體和堆記憶體的區別是什麼?
Java把記憶體劃分成兩種:一種是棧記憶體,一種是堆記憶體。兩者的區別是:

1)棧記憶體:在函式中定義的一些基本型別的變數和物件的引用變數都在函式的棧記憶體中分配。 當在一段程式碼塊定義一個變數時,Java就在棧中為這個變數分配記憶體空間,當超過變數的作用域後,Java會自動釋放掉為該變數所分配的記憶體空間,該記憶體空間可以立即被另作他用。

2)堆記憶體:堆記憶體用來存放由new建立的物件和陣列。在堆中分配的記憶體,由Java虛擬機器的自動垃圾回收器來管理。

Java中對異常是如何進行分類的?
異常整體分類:

1)Java異常結構中定義有Throwable類。 Exception和Error為其子類。

2)其中Exception表示由於網路故障、檔案損壞、裝置錯誤、使用者輸入非法情況導致的異常;

3)而Error標識Java執行時環境出現的錯誤,例如:JVM記憶體耗盡。

資料庫設計中常講的三正規化是指什麼?
1)第一正規化1NF(域的原子性)

如果資料庫表中的所有欄位值都是不可分解的原子值,就說明該資料庫表滿足了第一正規化

2)第二正規化2NF(表中除主鍵外的欄位都完全依賴主鍵)

第二正規化是在第一正規化基礎上建立的。第二正規化有兩個重點:(1)表中必須有主鍵;(2)其他非主屬性必須完全依賴主鍵,不能只依賴主鍵的一部分(主要針對聯合主鍵而言)。

3)第三正規化3NF(表中除主鍵外的欄位都完全直接依賴,不能是傳遞依賴)

不能是傳遞依賴,即不能存在:非主鍵列 A 依賴於非主鍵列 B,非主鍵列 B 依賴於主鍵的情況。第二正規化和第三正規化區分的關鍵點:2NF:非主鍵列是否完全依賴於主鍵,還是依賴於主鍵的一部分;3NF:非主鍵列是直接依賴於主鍵,還是直接依賴於非主鍵列。

Java中的執行緒池共有幾種?
Java四種執行緒池

第一種:newCachedThreadPool

  建立一個可根據需要建立新執行緒的執行緒池,但是在以前構造的執行緒可用時將重用它們。

第二種:newFixedThreadPool

  建立一個指定工作執行緒數量的執行緒池

第三種:newScheduledThreadPool

建立一個執行緒池,它可安排在給定延遲後執行命令或者定期地執行。

第四種:newSingleThreadExecutor

  建立一個使用單個 worker 執行緒的 Executor,以無界佇列方式來執行該執行緒。

volatile和synchronized區別

volatile和synchronized簡介:

在Java中,為了保證多執行緒讀寫資料時保證資料的一致性,可以採用兩種方式:

  1)使用synchronized關鍵字

  2)使用volatile關鍵字:用一句話概括volatile,它能夠使變數在值發生改變時能儘快地讓其他執行緒知道。

兩者的區別:

1)volatile本質是在告訴jvm當前變數在暫存器中的值是不確定的,需要從主存中讀取,synchronized則是鎖定當前變數,只有當前執行緒可以訪問該變數,其他執行緒被阻塞住.

2)volatile僅能使用在變數級別,synchronized則可以使用在變數,方法.

3)volatile僅能實現變數的修改可見性,而synchronized則可以保證變數的修改可見性和原子性.

4)volatile不會造成執行緒的阻塞,而synchronized可能會造成執行緒的阻塞.

Spring的特性

1.方便解耦,簡化開發

通過Spring提供的IoC容器,我們可以將物件之間的依賴關係交由Spring進行控制,避免硬編碼所造成的過度程式耦合。

2.AOP程式設計的支援

通過Spring提供的AOP功能,方便進行面向切面的程式設計。

3.宣告事物的支援

在Spring中,我們可以從單調煩悶的事務管理程式碼中解脫出來,通過宣告式方式靈活地進行事務的管理,提高開發效率和質量。

4.方便程式的測試

可以用非容器依賴的程式設計方式進行幾乎所有的測試工作。例如:Spring對Junit4支援,可以通過註解方便的測試Spring程式。

5.方便整合各種優秀框架

Spring不排斥各種優秀的開源框架,相反,Spring可以降低各種框架的使用難度,Spring提供了對各種優秀框架(如Struts,Hibernate、Hessian、Quartz)等的直接支援。

6.降低Java EE API的使用難度

Spring對很多難用的Java EE API(如JDBC,JavaMail,遠端呼叫等)提供了一個薄薄的封裝層,通過Spring的簡易封裝,這些Java EE API的使用難度大為降低。

spring aop的應用場景:

AOP用來封裝橫切關注點,具體可以在下面的場景中使用

Authentication 許可權

Caching 快取

Context passing 內容傳遞

Error handling 錯誤處理

Lazy loading 懶載入

Debugging 除錯

logging, tracing, profiling and monitoring 記錄跟蹤 優化 校準

Performance optimization 效能優化

Persistence 持久化

Resource pooling 資源池

Synchronization 同步

Transactions 事務

Mybaits中#和$區別

1)${}是Properties檔案中的變數佔位符,它可以用於標籤屬性值和sql內部,屬於靜態文字替換,比如${driver}會被靜態替換為com.mysql.jdbc.Driver。

2)#{}是sql的引數佔位符,Mybatis會將sql中的#{}替換為?號,在sql執行前會使用PreparedStatement的引數設定方法,按序給sql的?號佔位符設定引數值,比如ps.setInt(0, parameterValue),#{item.name}的取值方式為使用反射從引數物件中獲取item物件的name屬性值,相當於param.getItem().getName()。

排序都有哪幾種方法?請列舉。用JAVA 實現一個快速排序。

排序的方法有:

插入排序(直接插入排序、希爾排序),交換排序(氣泡排序、快速排序),選擇排序(直接選擇排序、堆排序),歸併排序,分配排序(箱排序、基數排序);

快速排序的虛擬碼:

//使用快速排序方法對a[ 0 :n- 1 ]排序

從a[ 0 :n- 1 ]中選擇一個元素作為middle,該元素為支點;

把餘下的元素分割為兩段left 和right,使得left 中的元素都小於等於支點,

而right 中的元素都大於等於支點;

遞迴地使用快速排序方法對left 進行排序;

遞迴地使用快速排序方法對right 進行排序;

所得結果為left + middle + right。

快速排序的Java程式碼實現如下:

小編公眾號已正式開通啦!!!  會定期分享包括但不侷限於 java技術性文章, 系統化的視訊學習資源, 職場發展規劃,行業動態等等, 注: 公眾號純屬個人所有, 不存在任何收費專案, 更不存在任何培訓資訊, 純屬公益分享, 所有視訊學習資源均免費! 感謝大家的支援