從7月2號開始,到7月21號結束,14個工作日,參加了15場面試。其中:
滴滴:面4場
美團:面3場
自如:面2場
小米:面3場
去哪兒:面1場
Boss直聘:面2場
工作3年,終於拿到了心儀的offer,在這裡做一個記錄。
因平時上班事情比較多,再加上面試比較密集,所以沒能及時的對每一次面試做一個覆盤,導致面試遇到的好多東西都已經忘了,所以這裡就只能撿我在微信檔案助手裡面的幾個有意思的記錄來寫了。
好記性不如爛筆頭,寫出來一是給自己做一個筆記,二是也希望分享出來能對其他朋友有所幫助。
美團二面
1、如果因為一些原因,線上Redis掛了,然後所有請求打到資料庫層導致資料庫也掛了,這時該怎麼進行恢復?
就以我三年的工作經驗來說顯然是超出了我的範圍,沒遇到過這樣的場景,平時也沒怎麼想過,然後當時的第一思路就是先做限流,然後逐步恢復Redis和資料庫。
很明顯,當時這個問題我回答的並沒有讓面試官滿意,但是實在所見有限,沒有其他思路了,歡迎路過的朋友給一些其他思路。
2、Spring裡面的bean id是否允許重複?如果允許重複的話重複了怎麼辦?如果不允許重複是怎麼處理的?
因為在我的個人簡歷裡面寫了自己深入閱讀過Spring原始碼的,所以這一個問題明顯是就這一項的發問,當時自己確實記得是不允許重複的,所以回答的是不允許重複,如果重複了丟擲bean重複定義的異常。然後面試官當場給我指出來說是允許重複的,如果重複了的話後載入進來的是覆蓋前面的,不會做拋錯。
針對這個問題,我重新翻閱了一下Spring原始碼,原來我記混淆了,會丟擲異常的是beanDefinition,處理邏輯如下方法:
DefaultListableBeanFactory.registerBeanDefinition
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
// 刪掉了一部分程式碼
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
if (existingDefinition != null) {
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
}
else if (existingDefinition.getRole() < beanDefinition.getRole()) {
if (logger.isInfoEnabled()) {
logger.info("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
existingDefinition + "] with [" + beanDefinition + "]");
}
}
else if (!beanDefinition.equals(existingDefinition)) {
if (logger.isDebugEnabled()) {
logger.debug("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
else {
if (logger.isTraceEnabled()) {
logger.trace("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
// 刪掉了一部分程式碼
}
// 刪掉了一部分程式碼
}
可以看出,beanDefinition重複是否會丟擲異常也是結合配置來說的。而對於例項id重複,那麼直接是覆蓋了,如程式碼:
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
當然,這個問題的前置還有Spring的bean生命週期系列,回答完後問到這裡的。
3、G1對宿主機有什麼要求?
這個當時回答不上來,然後也沒找到什麼有用的資料;
4、堆設定有什麼注意事項?
留出可用空間的20%給元空間。
小米一面
1、手寫Dubbo的加權隨機演算法
背景是我簡歷上面寫了深入瞭解Dubbo,對Dubbo原始碼有深入瞭解,然後面試官就問出了這個問題。比較簡單,寫出的程式碼如下:
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class WeightedRandom {
private static Random random = new Random();
public static void main(String[] args) {
List<Node> list = new ArrayList();
list.add(new Node("節點一(5)",5));
list.add(new Node("節點二(3)",3));
list.add(new Node("節點三(2)",2));
for (int i = 0;i < 10000;i++) {
Node cur = selected(list);
// 統計操作
}
// 列印結果
}
private static Node selected(List<Node> list) {
if (list == null || list.size() == 0) {
return null;
} else if (list.size() == 1) {
return list.get(0);
}
int totalWeight = 0;
boolean sameWeight = true;
int firstWeight = 0;
for (int i = 0;i < list.size();i++) {
if (i == 0) {
totalWeight += list.get(0).weight;
firstWeight = list.get(0).weight;
} else {
totalWeight += list.get(i).weight;
if (list.get(i).weight != firstWeight) {
sameWeight = false;
}
}
}
if (!sameWeight) {
int curVal = random.nextInt(totalWeight);
for (int i = 0;i < list.size();i++) {
curVal -= list.get(i).weight;
if (curVal < 0) {
return list.get(i);
}
}
}
return list.get(random.nextInt(list.size()));
}
private static class Node {
String name;
int weight;
public Node(String name,int weight) {
this.name = name;
this.weight = weight;
}
}
}
2、Spring獲取代理物件解決事務失效的問題。
調Spring對應的api,這樣做會把框架程式碼耦合在自己的業務程式碼中;
自己注入自己,需要注意死迴圈的問題;
儘量避免這種同一個Service中非事務方法呼叫事務方法的情況。
滴滴二面
1、一個升序陣列,隨機選擇一個旋轉節點。右邊的有序段放到左邊,依然保持有序;左邊的有序段放到右邊,依然保持有序。然後從這個陣列中查詢某個數。
這個問題本質還是找那個旋轉點,當知道那個旋轉點後,無非就是在左邊或者右邊進行二分查詢。
當時回答這個問題的主要思路就是從一個陣列兩頭開始,分別作為left和right,然後計算中間位置mid,然後在left和mid之間找新的left,在mid和right之間找新的right,不斷逼近從而找出那個旋轉節點,旋轉節點滿足條件:arr[index - 1] > arr[index] > arr[index + 1]。
美團一面
1、Spring和Mybatis是怎麼結合的?
這個問題當時沒有理解面試官的意圖,然後回答它們之間有一個整合包,這個整合包充當了一個介面卡的角色,然後面試官就沒有再問了。
2、mysql explain有哪些項?
常規問題,比如涉及的表、訪問方法、可能索引、實際使用的索引等。
3、dubbo協議
這一個也是針對簡歷來問的,聽到後心裡有點涼快,然後就老實回答自己對於一些核心流程程式碼確實看過,但是對於這樣底層的東西確實沒有怎麼了解過。
4、單連結串列找迴圈節點。
leetcode上的常規題了,幾分鐘就搞定了。
小米二面
1、順序讀取一億個整數,找出前100萬大的數字,記憶體限定大小為10M,後記憶體限定大小為5M。
我首先回答1個整型在記憶體中佔4個位元組,100萬個整數佔用4M,然後我在記憶體中載入200萬個整數分為2個組,排序然後合併選出前100萬大的數字,然後重新讀取100萬個數字繼續同樣的操作。
這時,面試官說將記憶體限制為5M。
很明顯,就是想問問大頂堆而已,然後就回答使用大頂堆,畢竟返回結果不要求嚴格有序,只要前100萬大就可以了。
小米二面面完後,還有三面的,但是我實在忍受不了那個三面面試官那牛逼哄哄的樣子,所以面到一半我就直接退出會議室了,面了這麼多場,遇到了一些態度很好的面試官,也遇到一些態度很差的面試官,就數小米這三面面試官的態度最他麼噁心。
在小米三面的時候我就已經拿到自己想要的offer了,所以那天面試也就是抱著聊的好玩的心態聊,並沒想去小米,結果著實把我噁心了。
去哪兒一面
1、stream和foreach區別?
有使用,但是沒有太多瞭解,就沒有回答出什麼。
2、zookeeper和nacos區別?nacos符合CP還是AP?
這個問題印象特別深,原本是沒有看過nacos官方對這一個介紹的,但是看過CAP理論,然後想到即使nacos掛了,nacos客戶端仍然可以通過本地快取列表繼續工作,所以果斷回答了AP。