最近一直在面試央串。面試了大約有10來家公司,有1000人以上的大公司约谈,也有50左右的小公司笔宿。時間倉促沒有準備充分,面試的機會雖然很多棱诱,但是面試時表現(xiàn)的一般泼橘。通過這10來場的面試,我對自己的知識體系薄弱環(huán)節(jié)有了較為清楚的認識迈勋。這里記錄一些我在面試中遇到的比較常見的面試題炬灭。這只是其中的小小一部分。
0. 數(shù)據(jù)庫
好久沒寫代碼了靡菇,SQL語句很生疏重归,導致我面試的時候簡單的語法都忘了,吃了很大虧厦凤。這里推薦一篇大佬的博客鼻吮。該博客中收錄了常見的MySQL面試題和筆試題。SQL復習
1. 基本數(shù)據(jù)類型和引用數(shù)據(jù)類型的區(qū)別
問題分析:這個問題不是說有多難泳唠,只是我們平時專注于代碼邏輯狈网,很容易忽視代碼的底層原理。
示例答案:
- 基本數(shù)據(jù)類型在創(chuàng)建時笨腥,在棧上給其劃分一塊內存拓哺,將數(shù)值直接存儲在棧上。
- 引用數(shù)據(jù)類型在被創(chuàng)建時脖母,首先要在棧上給其引用(句柄)分配一塊內存士鸥,而對象的具體信息都存儲在堆內存中,然后由棧上的引用指向堆中的對象的地址谆级。
這道題主要考察JVM中內存模型烤礁,這塊需要重點理解。
JVM區(qū)域劃分為:程序計數(shù)器肥照,虛擬機棧脚仔,堆,方法區(qū)舆绎,本地方法棧五個區(qū)域鲤脏。
①程序計數(shù)器: Java代碼會被翻譯成字節(jié)碼饺蔑,不同字節(jié)碼指令指揮計算機干不同的事平窘。程序計數(shù)器是用來記錄每個線程當前執(zhí)行的指令的位置。因為程序可以是多線程的,所以每個線程都有自己的程序計數(shù)器惶室。
②Java虛擬機棧:Java代碼執(zhí)行時泽本,一定是線程執(zhí)行某個方法中的代碼胧沫。JVM中有一塊區(qū)域用來保存每個方法內的局部變量等數(shù)據(jù)拭抬,這個區(qū)域就是Java虛擬機棧。為什么需要這個區(qū)域沦疾?因為每個線程都會去執(zhí)行各種方法的代碼称近,方法內還會嵌套調用其他的方法,所以每個線程都要有自己的Java虛擬機棧曹鸠。
調用執(zhí)行任何方法時煌茬,都會給方法創(chuàng)建棧幀,然后入棧彻桃。
③Java堆內存:用來存放Java中的創(chuàng)建的實例對象坛善。比如Student對象。那么Java虛擬機棧中的變量student就會存放該對象的地址邻眷,或者說student指向了該對象眠屎。
④Java方法區(qū):主要還是存放我們自己寫的各種類相關的信息。
⑤本地方法棧:Java執(zhí)行時會調用非Java代碼肆饶,執(zhí)行native方法改衩,本地方法棧用來存放native方法的局部變量表等信息。
2. 檢查時異常和運行時異常的區(qū)別
這個問題容易忽略驯镊。
Java中把所有的非正常情況分為兩種:異常(Exception)和錯誤(Error)葫督,他們都繼承Throwable父類。
Java的非正常情況可以分為檢查異常
和非檢查異常
板惑。
其中Exception異常分為運行時異常
和非運行時異常
橄镜。
-
檢查異常:
- 概念:就是編譯器要求你必須要處理的異常。你的代碼還沒有運行時冯乘,編譯器就會檢查你的代碼洽胶,對于可能出現(xiàn)的異常你必須使用try...catch...或者throws exception。
- 處理:①使用throws exception往上拋出裆馒,一直可以拋到Java虛擬機來處理姊氓。②使用try...catch...
- 范圍:除了RuntimeException與其子類,錯誤Error以外的喷好,差不多都是檢查異常翔横。
-
非檢查異常:
- 概念:編譯器不要求強制處置的異常,雖然可能出錯梗搅,但是不會在編譯時檢查棕孙。
- 處理:①try..catch...②繼續(xù)拋出③不處理
- 范圍:RuntimeException與其子類,Error錯誤些膨。
運行時異常:RuntimeException及其子類
非運行時異常:異常中除了RuntimeException及其子類以外都是非運行時異常蟀俊。
3. Spring相關
如果你使用SSM框架,基本Spring一上來就問這幾個問題订雾,必須非常熟悉肢预。
IOC:控制反轉,傳統(tǒng)的Java開發(fā)模式中洼哎,當需要一個對象時烫映,我們會自己使用new或者getInstance等直接或者間接調用構造方法創(chuàng)建一個對象。而在Spring中噩峦,Spring容器使用了工廠模式為我們創(chuàng)建了所需要的對象锭沟,不需要我們自己創(chuàng)建了,直接調用Spring提供的對象就可以了识补。
DI:依賴注入族淮,Spring使用JavaBean對象的set方法或者帶參數(shù)的構造方法為我們在創(chuàng)建對象時將其屬性自動設置所需要的值的過程,就是依賴注入的思想凭涂。
AOP面向切面編程:在面向對象編程思想中祝辣,我們將事物縱向抽取成一個個的對象。而在面向切面編程中切油,我們將一個個的對象某些類似的方面橫向抽成一個切面蝙斜,對這個切面進行一些如權限控制,事物管理澎胡,記錄日志等公用操作處理的過程就是面向切面編程的思想孕荠。AOP的底層是動態(tài)代理,如果目標對象是接口采用JDK動態(tài)代理攻谁,如果是類采用Cglib方式實現(xiàn)動態(tài)代理稚伍。
動態(tài)代理的原理可以看看我之前寫的一篇:動態(tài)代理
4. Java 中的 HashMap 的工作原理是什么?
面試官開始問你基礎的時候巢株,很多都從HashMap開始槐瑞。
- Java 中的 HashMap 是以鍵值對(key-value)的形式存儲元素的。HashMap 需要一個 hash 函數(shù)阁苞,它使用 hashCode()和 equals()方法來向集合/從集合添加和檢索元素困檩。當調用 put()方法的時候,HashMap 會計算 key 的 hash 值那槽,然后把鍵值對存儲在集合中合適的索引上悼沿。如果 key已經(jīng)存在了,value 會被更新成新值骚灸。HashMap 的一些重要的特性是它的容量(capacity)糟趾,負 載因子(load factor)和擴容極限(threshold resizing)。
5. HashMap 和 Hashtable 有什么區(qū)別?
HashMap 和 Hashtable 都實現(xiàn)了Map 接口义郑,因此很多特性非常相似蝶柿。但是,他們有以下不同點:
- HashMap 允許鍵和值是 null非驮,而Hashtable 不允許鍵或者值是 null交汤。
- Hashtable 是同步的,而 HashMap 不是劫笙。因此芙扎,HashMap 更適合于單線程環(huán)境,而 Hashtable適合于多線程環(huán)境填大。
- HashMap 提供了可供應用迭代的鍵的集合戒洼,因此,HashMap 是快速失敗的允华。另一方面圈浇,Hashtable 提供了對鍵的列舉(Enumeration)。一般認為 Hashtable 是一個遺留的類例获。
6. SQL優(yōu)化
這里只是一些SQL優(yōu)化的思路汉额,遠遠不止這些。
- 使用JOIN的時候榨汤,應該用小的結果驅動大的結果『left join左邊表結果盡量小蠕搜,如果有條件應該放到左邊先處理』
- 盡量把牽涉到多表聯(lián)合查詢拆分多個query,因為連表查詢效率低收壕,容易到之后鎖表和阻塞妓灌。
- limit的基數(shù)比較大時使用between
- 盡量避免在列上做運算,這樣導致索引失效蜜宪。
select * from admin where year(admin_time)>2014
優(yōu)化為:
select * from admin where admin_time>'2014-01-01'
7. Redis
談到Redis的話可以從以下幾個方面簡單說說虫埂。
可以看看之前寫的Redis復習一下:Redis
本質上是一個key~value類型的內存數(shù)據(jù)庫。
數(shù)據(jù)結構:String Hash List Set Sorted Set
應用場景:會話緩存圃验、全頁緩存掉伏、隊列、排行榜
-
Memcache和Redis的主要區(qū)別:
- 前者是把數(shù)據(jù)全部存在內存中澳窑,數(shù)據(jù)不能超過內存的大小斧散,斷電后數(shù)據(jù)庫會掛掉。后者有部分存在硬盤上摊聋,這樣能保證數(shù)據(jù)的持久化鸡捐。
-
持久化:
- RDB持久化:該機制可以在指定的時間間隔內生成數(shù)據(jù)集的時間點快照。(適合用來備份)
- AOF持久化:記錄服務器執(zhí)行的所有寫操作命令麻裁,并在服務器啟動時箍镜,通過重新執(zhí)行這些命令來還原數(shù)據(jù)集源祈。AOF文件中的命令全部以Redis協(xié)議的格式來保存,新命令會被追加到文件的尾部色迂。(AOF文件是一個只進行追加操作的日志文件)
8. RabbitMQ
明白MQ的概念香缺、原理、使用場景脚草。
- 概念:MQ全稱是Message Queue赫悄,可以理解為消息隊列的意思,簡單來說就是消息以管道的方式進行傳遞馏慨。RabbitMQ是一個實現(xiàn)了高級消息隊列協(xié)議的消息隊列服務,用Erlang語言的姑隅。
- 使用場景:比如秒殺系統(tǒng)中写隶,當用戶訪問量很大時系統(tǒng)會提示我們排隊結算。這種排隊結算就使用到了消息隊列讲仰,生產(chǎn)者生產(chǎn)的消息放入通道中一個個地被消費慕趴,而不是某個時間內突然出現(xiàn)大批量的查詢新增把數(shù)據(jù)庫給搞宕機了。所以RabbitMQ的作用是削峰填谷鄙陡。
- 工作機制:
- 生產(chǎn)者:創(chuàng)建消息冕房,發(fā)送消息到服務器
- 消費者:接受確認消息
- 代理:RabbitMQ本身,不產(chǎn)生消息趁矾,只是傳遞消息耙册。
- 發(fā)送原理:首先要連接RabbitMQ。應用程序和RabbitMQ服務器之間會創(chuàng)建一個TCP連接毫捣,一旦TCP打開連接详拙,并且通過了認證(認證就是嘗試連接RabbitMQ服務器之前發(fā)送給服務器的連接信息,用戶名和密碼)蔓同,應用程序和和Rabbit就創(chuàng)建了一條AMQP的信道饶辙。信道是創(chuàng)建在“真實”TCP上的虛擬連接,AMQP命令都是通過信道發(fā)送出去的斑粱,每個信道都會有一個唯一的ID弃揽,不論是發(fā)布消息,訂閱隊列或者介紹消息都是通過信道完成的则北。
- 為什么不通過TCP直接發(fā)送命令矿微?
- 對于操作系統(tǒng)來說創(chuàng)建和銷毀TCP會話是非常昂貴的開銷,假設高峰期每秒有成千上萬條連接咒锻,每個連接都要創(chuàng)建一條TCP會話冷冗,這就造成了TCP連接的巨大浪費,而且操作系統(tǒng)每秒能創(chuàng)建的TCP也是有限的惑艇,因此很快就會遇到系統(tǒng)瓶頸蒿辙。
- 如果我們每個請求都使用一條TCP連接拇泛,既滿足了性能的需要,又能確保每個連接的私密性思灌,這就是引入信道概念的原因俺叭。
- 持久化工作原理:Rabbit會將你的持久化消息寫入磁盤上的持久化日志文件,等消息被消費之后泰偿,Rabbit會把這條消息標識為等待垃圾回收
- RabbitMQ防止消息丟失熄守?
- 客戶端丟失消息確認:RabbitMQ引入了消息確認機制,當消息處理完成后耗跛,給Server端發(fā)送一個確認消息裕照,來告訴服務端可以刪除該消息了,如果連接斷開的時候调塌,Server端沒有收到消費者發(fā)出的確認信息晋南,則會把消息轉發(fā)給其他保持在線的消費者。
9. Collection
- List接口:
- arrayList:底層實現(xiàn)基于動態(tài)數(shù)組羔砾,隨機的訪問查詢比較快负间,插入,刪除姜凄,修改比較慢政溃,線程不安全。
- LinkedList 底層實現(xiàn)基于鏈表态秧,所以查詢慢董虱,修改,刪除屿聋,插入快空扎,線程不安全。
- Vector :也是基于數(shù)組實現(xiàn)的润讥,和arrayList的區(qū)別是線程安全转锈,效率低。
- Set接口:不可重復
- HashSet: 使用哈希算法去重復, 效率高
- LinkedHashSet: HashSet的子類, 去重復并且保留存儲順序
- TreeSet: 可以用指定的比較方法進行排序