實用乾貨!P6級Java面試題歸總

陝西優就業發表於2019-11-21

想必大家都很好奇高階程式設計師的面試題會考什麼?那今天陝西優就業小編就帶大家來看看。

一、String stringBuffer和stringBuilder

String:適用於少量字串操作的情況,為字串常量,即物件一旦建立之後物件是不可更改的。

StringBuffer:適用多執行緒下字元緩衝區進行大量操作的情況。屬於執行緒安全。

StringBuilder:適用於單執行緒下在字元緩衝區進行大量操作的情況。屬於執行緒不安全。

StringBuffer與StringBuilder均為字串變數,物件是變數,即可以更改。StringBuilder所有方面都沒有被synchronized修飾,它的效率比StringBuffer要高。

二、HashMap的底層實現原理

HashMap底層是陣列+連結串列實現的,它是一個entry類的陣列,entry中包含key和value的值,允許key、value可以為null,透過key的hashcode計算在這個陣列所在位置,遍歷這個連結串列從而查詢到值,hashMap預設的初始化容器大小為16,之後每次擴充為原來的2倍。屬於執行緒不安全的。

在JDK1.7及以前,HashMap中維護著Entry,Entry中維護著key,value以及hash和next指標,而整個HashMap實際就是一個Entry陣列。

當向 HashMap 中 put 一對鍵值時,它會根據 key的 hashCode 值計算出一個位置,該位置就是此物件準備往陣列中存放的位置。

如果該位置沒有物件存在,就將此物件直接放進陣列當中;如果該位置已經有物件存在了,則順著此存在的物件的鏈開始尋找(為了判斷是否是否值相同,map不允許鍵值對重複),如果此鏈上有物件的話,再去使用 equals方法進行比較,如果對此鏈上的每個物件的 equals 方法比較為 false,則將該物件放到陣列當中,然後將陣列中該位置以前存在的那個物件連結到此物件的後面。

get方法類似,透過key取hash找到陣列的某個位置,然後遍歷這個陣列上的每個Entry,直到key值equals則返回。

如果Hash碰撞嚴重,那麼JDK1.7中的實現效能就很差,因為每次插入都要遍歷完整條鏈去檢視key值是否重複,每次get也要遍歷整個鏈,在JDK1.8中,由於連結串列的查詢複雜度為O(n),而紅黑樹的查詢複雜度為O(logn),JDK1.8中採用連結串列/紅黑樹的方式實現HashMap,達到某個閥值時,連結串列轉成了紅黑樹。

三、HashMap和Concurrent HashMap區別, Concurrent HashMap 執行緒安全嗎, ConcurrentHashMap如何保證執行緒安全?

HashMap不是執行緒安全的,ConcurrentHashMap是執行緒安全的,HashMap內部維護著一個Entry陣列,而ConcurrentHashMap內部有一個Segment段,它將大的HashMap切分成若干個段(小的HashMap),然後讓資料在每一段上Hash,這樣多個執行緒在不同段上的Hash操作一定是執行緒安全的,所以只需要同步同一個段上的執行緒就可以了,這樣實現了鎖的分離,大大增加了併發量。ConcurrentHashMap的實現中還使用了不變模式final和volatile來保障執行緒安全

四、HashMap的put方法做了哪些操作

他會根據key的hashcode重新計算hash值,根據hash值得到這個元素在資料中的位置,如果陣列在該位置上已經存放有其他元素了,那麼在這個位置上的元素將以連結串列的形式存放,新加入的放在鏈頭,最先加入的放在鏈尾。

五、HashMap的缺點

HashMap不支援併發操作,所以不適用於多執行緒環境,在高併發狀態下,如果產生同時put操作,並且在put時剛好遇上要擴容,可能會形成鏈環,如果get的key的hashcode值剛好在鏈環的位置,而這個key對應的值為null或不存在就會進入死迴圈,耗盡cpu記憶體。

六、ConcurrentHashMap

底層是陣列+紅黑樹+連結串列實現,可以替代HashTable,因為使用了多個鎖代替hashTable中的單個鎖,也就是鎖分離技術,hashTable是鎖住了整個陣列導致效率特別低,屬於執行緒安全。

七、Springmvc的工作原理

使用者傳送請求至前端控制器DispatcherServlet,DispatcherServlet收到請求呼叫handlerMapping處理器對映器,解析請求對應的handler,開始由handlerAdapter介面卡處理請求,並處理相應的業務邏輯並返回一個ModelAndView物件,根據返回的modelAndView選擇一個合適檢視解析器返回給DispatcherServlet,檢視解析器根據view和model渲染頁面。

八、集合的父類及各子類的區別

Collection

├List 允許重複值、有序容器,保持了每個元素的插入順序

│├LinkedList 執行緒不安全增刪改速度快,基於連結串列資料結構

│├ArrayList 執行緒不安全查詢速度快,基於動態陣列結構

│└Vector 執行緒安全

│└Stack

├set 不允許重複值、無序容器,無法保證元素的儲存順序,可以透過TreeSet的comparator或者comparable維護一個排序順序

│├HashSet 執行緒不安全無序(存入與取出時順序不同)不重複,無索引,底層hash表結構查詢刪除快,增改慢。

│├TreeSet 是sortedSet介面的唯一實現,可以進行排序

九、什麼是執行緒安全與不安全

執行緒安全是多個執行緒訪問時,採用了加鎖機制,當一個執行緒訪問該類的某個資料時,進行保護,其他執行緒不能進行訪問,直到該執行緒讀取完,其他執行緒才可使用,不會出現資料不一致或者資料汙染。

執行緒不安全就是不提供資料訪問保護,有可能出現多個執行緒後更改資料造成所得到資料時髒資料。

十、為什麼使用reids,用redis都做了些什麼

Redis是一個開源的key-value型資料庫,執行在記憶體,速度快,同時支援持久化,支援的資料結構豐富(String,list,set,sorted set,hash),支援訂閱釋出功能。

String:(常用命令get,set,incr,decr,mget)常規的key-value快取應用。統計訪問次數,關注人數。

Hash(常用命令hget,hset,hgetall)省市區聯動,使用者資訊

List(常用命令 Ipush,rpush,Ipop)使用者關注列表

Set 註冊使用者使用者名稱不能重複,使用set記錄註冊使用者

十一、Jvm如何調優

VisualVM:jdk自帶,功能強大

堆資訊檢視:觀察記憶體釋放情況、集合類檢查、物件樹-----(檢視堆空間的大小分配【年輕代、年老代、持久代分配】、提供即時的垃圾回收功能、垃圾監控),可以解決年老代年輕代大小劃分是否合理、記憶體洩漏、垃圾回收演算法設定是否合理。

執行緒監控:可以檢視執行緒在系統中的數量,各個執行緒都處在什麼狀態下、死鎖檢查

熱點分析:cpu熱點---檢查系統哪些方面佔用大量cpu時間,記憶體熱點-------檢查哪些物件在系統中的數量最大。

記憶體洩漏檢查:在錯誤的使用下導致使用完畢的資源無法回收,引起系統錯誤。常表現年老代空間被佔滿(java heap space)一般根據垃圾回收前後情況對比,同時根據物件引用情況分析,基本可以找到洩漏點。

持久代被沾滿:無法為新的class分配儲存空間而引發的異常,在java大量的反射的使用會造成,大量動態反射生成的類不斷被載入。解決:-XX:MaxPermSize=16m

堆疊溢位:一般是遞迴沒返回,或者迴圈呼叫造成

執行緒池棧滿:java中一個執行緒空間大小是有限的,在jdk5以後這個值是1m。解決:增加執行緒棧大小,-Xss2m

十二、GC垃圾回收機制

什麼時候:eden滿了minor gc,升到老年代的物件大於老年代剩餘空間full gc,或者小於時被HandlePromotionFailure引數強制full gc

對什麼東西:從root搜尋不到,而且經過第一次標記,清理後仍然沒有復活的物件。

做什麼事情:刪除不使用的物件,騰出記憶體空間。

演算法:

1、標記-清除:分為標記和清除兩個階段,首先標記出所有需要回收的物件,標記完成後統一回收所有被標記的物件。

2、複製演算法:它將可用的記憶體分為兩塊,每次只用其中一塊,當這一塊記憶體用完了,就將還存活的物件複製到另一塊上,然後再把已經使用過的記憶體空間一次性清理掉。

3、標記-整理演算法:是讓所有存活的物件都向一端移動,然後直接清理掉邊界以外的記憶體。

十三、 JVM如何GC,新生代,老年代,持久代,都儲存哪些東西?

JVM透過可達性(可觸及性)分析演算法標記出哪些物件是垃圾物件,然後將垃圾物件進行回收,在新生代中採用複製演算法,在老年代中採用標記清理或標記壓縮演算法。

新生代儲存了新new出的物件,老年代儲存了大的物件和多次GC後仍然存在的老年物件,持久代儲存了類資訊,常量(JDK7中String常量池被移到堆中),靜態變數(JDK7中被移到了Java堆),類方法

十四、 強引用、軟引用、弱引用、虛引用的區別

強引用:是最難被GC回收的,寧可虛擬機器丟擲異常,中斷程式,也不會去回收該物件。(Object o=new Object())

軟引用:非必須引用,記憶體溢位之前進行回收。軟引用主要使用者實現類似快取的功能,在記憶體足夠的情況下直接透過軟引用取值,無需從繁忙的真實來源查詢資料,提升速度;當記憶體不足時,自動刪除這部分快取資料,從真正的來源查詢這些資料。

弱引用:第二次垃圾回收時回收。弱引用主要用於監控物件是否已經被垃圾回收器標記為即將回收的垃圾,可以透過弱引用的isEnQueued方法返回物件是否被垃圾回收器標記。

虛引用:垃圾回收時回收,無法透過引用取到物件值。虛引用主要用於檢測物件是否已經從記憶體中刪除。

十五、Spring的原理

內部核心是ioc,動態注入,讓一個物件的建立不用new了,可以自動生成,這其實就是利用了java裡的反射,反射其實就是在執行時動態的去建立、呼叫物件,spring就是在執行時,跟xml spring的配置檔案來動態的建立物件,和呼叫物件的方法。

Spring還有一個核心就是AOP面向切面程式設計,可以為某一類物件進行監督和控制從而達到堆一個模組擴充的功能。這些都是透過配置類達到的。

十六、Aop如何實現

靜態代理:由程式設計師建立或特定工具自動生成原始碼,再對其編譯。在程式執行時,代理類.class檔案就已經存在了

動態代理:在程式執行時,運用發射機制動態建立而成。

Cglib動態代理:針對類實現的代理。它的原理是對指定的目標類生成一個子類,並覆蓋其中方法實現增強,但因為採用的是繼承,所以不能對final修飾的類進行代理。

JDK的動態代理依靠介面實現,如果有些類沒有實現介面,則不能使用jdk代理,就要使用cglib代理了。

十七、MySQL如何最佳化

使用查詢快取最佳化查詢。(例如NOW(),RAND()或其他SQL函式都不會開啟查詢快取,因為返回是會不定的易變得,所以你需要的就是一個變數來替代mysql的函式,從而開啟快取)

使用EXPLANIN關鍵字檢測查詢(可以使我們知道MYSQL是如何處理SQL語句的,幫助分析查詢語句或是表結構效能瓶頸;索引主鍵是如何被利用的,資料表是如何被搜尋或排序的,語句格式:EXPLAIN+SELECT語句)

當只有一行資料時使用LIMIT 1(可以增加效能,會查到第一條資料後停止搜尋)

為搜尋欄位建立索引(普通索引INDEX:適用於name、email等一般屬性,唯一索引UNIQUE:要求索引欄位值在表中是唯一的,唯一索引允許有空值。適用於身份證號碼、使用者賬戶等,全文索引:適用於VARCHAR和TEXT型別欄位)

在jion表的時候使用相當型別的列,並將其索引(存在很多jion查詢時,保證兩個表中jion的欄位時被建立索引的,這樣mysql會啟動最佳化JION的sql語句機制)

避免使用 *

永遠為每一張表設定一個ID主鍵

儘可能的不要賦值為NULL(會佔用儲存空間,程式判斷更加複雜,索引不儲存null值,使用not null約束以及預設值。)

固定長度的表會更快(容易計算下一個資料的偏移量,容易被快取和重建。)

垂直分割:是一種把資料庫中的表按列變成幾張表的方法,這樣可以降低表的複雜度和欄位數目

拆分大的或(這兩個大操作會鎖表,這樣別的操作就進不來了,可以使用LIMIT控制操作記錄的數量)


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69902581/viewspace-2665193/,如需轉載,請註明出處,否則將追究法律責任。

相關文章