1. 程式人生 > >阿裏、華為、騰訊Java技術面試題精選

阿裏、華為、騰訊Java技術面試題精選

可見性 告訴 api 內存劃分 針對 流程 容量 ont ges

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

類的加載指的是將類的.class文件中的二進制數據讀入到內存中,將其放在運行時數據區的方法去內,然後在堆區創建一個java.lang.Class對象,用來封裝在方法區內的數據結構。類的加載最終是在堆區內的Class對象,Class對象封裝了類在方法區內的數據結構,並且向Java程序員提供了訪問方法區內的數據結構的接口。

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

類加載有三種方式:

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技術面試題精選