面試記錄 2019-06-19 上午 (掛)

中軟
無筆試,問的問題都很基礎灸异,但是自己都沒答好府适,腦殼是懵的。一剛開始答得不對绎狭,面試官也不多做解釋细溅,越答越沒信心。

1儡嘶、equals 和 hashCode 的區(qū)別喇聊。

我答成了 String 的 == 與 equals 的區(qū)別。
... ...
變形問題:Set/HashMap 是如何去重的?

Object 的 equals 方法默認是兩個對象的引用的比較蹦狂,和 == 是一樣的誓篱,意思就是指向同一內存,地址則相等凯楔,否則不相等窜骄。

public boolean equals(Object obj) {
  return (this == obj);
}

Object 的 hashCode 是一個本地方法衣赶。

public native int hashCode();

This is typically implemented by converting the internal address of the object into an
integer, but this implementation technique is not required by the Java? programming language.

這句話看得我有點懵欧穴,Java 中的默認 hashCode 到底是不是地址轉換出來的妨退,有很多人把默認 toString 打印出來的 @ 后面當做地址畏梆。還是說默認是地址,但不是必須這樣實現趾娃?我覺得應該是后者扔水,默認就是地址舞骆,所以大家都不一樣廷没,但是允許重寫糊饱。不管一不一樣,Hash 取模就會有沖突颠黎。

總結: equals 比較兩個對象是否相等另锋,默認是比較地址,可以重寫狭归,應該具有對稱性夭坪、反射性、傳遞性过椎、一致性台舱。比如 String 重寫后是比較值。
hashCode 主要用于 hash 計算,不同對象的 hashCode 可以相同竞惋。要求 equals 為 true 的兩個對象的 hashCode 一定相等。通常重寫 equals 方法也要重寫 hashCode 方法灰嫉。
有人就喜歡鉆牛角尖拆宛,說不一定要重寫 hashCode 。是的讼撒,是不一定浑厚,因為 hashCode 主要用于 set/map 集合判重邏輯,只要你保證不用于 set/map 集合根盒,不重寫也不會有問題钳幅。

對于變形題目,Set/Map 怎么判重的:HashSet 的內部是實現 HashMap炎滞。

 public boolean containsKey(Object key) {
    return getNode(hash(key), key) != null;
}

重新計算 hash 值:

 static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

把 key 的 hashCode 高16位低16位進行異或敢艰,目的是為了保證高16位也參與運算,減少沖突册赛。

final Node<K,V> getNode(int hash, Object key) {
    Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
    if ((tab = table) != null && (n = tab.length) > 0 &&
        (first = tab[(n - 1) & hash]) != null) {
        if (first.hash == hash && // always check first node
            ((k = first.key) == key || (key != null && key.equals(k))))
            return first;
        if ((e = first.next) != null) {
            if (first instanceof TreeNode)
                return ((TreeNode<K,V>)first).getTreeNode(hash, key);
            do {
                if (e.hash == hash &&
                    ((k = e.key) == key || (key != null && key.equals(k))))
                    return e;
            } while ((e = e.next) != null);
        }
    }
    return null;
}

這是1.8版本的钠导,hash 取模看對應桶是否為空森瘪,為空直接加入牡属;不為空從第一個開始比較 hash 值是否相同,再比較地址是否相同或者 key != null 比較 equals扼睬。
1.8 加入了紅黑樹逮栅,所以這里有個節(jié)點類型的判斷。

2窗宇、Spring MVC 的執(zhí)行過程措伐。

雖然源碼自己也看了很多遍,還是說的不利索担映。

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    HttpServletRequest processedRequest = request;
    HandlerExecutionChain mappedHandler = null;
    boolean multipartRequestParsed = false;

    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

    try {
        ModelAndView mv = null;
        Exception dispatchException = null;

        try {
            processedRequest = checkMultipart(request);
            multipartRequestParsed = (processedRequest != request);

            //  根據請求的 url 找 Handler废士,返回一個 HandlerExecutionChain。
            mappedHandler = getHandler(processedRequest);
            if (mappedHandler == null) {
                                // 沒找到蝇完,發(fā)出異常
                noHandlerFound(processedRequest, response);
                return;
            }

            // 為 handler 找 adapter 適配器 官硝。
            HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

            // Process last-modified header, if supported by the handler.
            String method = request.getMethod();
            boolean isGet = "GET".equals(method);
            if (isGet || "HEAD".equals(method)) {
                long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                    return;
                }
            }
                        // 循環(huán)執(zhí)行 pre 攔截器
            if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                return;
            }

            // 真正調用 handler,返回 modelAndView短蜕,如果使用 @RestController 注解氢架,返回空.
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

            if (asyncManager.isConcurrentHandlingStarted()) {
                return;
            }

            applyDefaultViewName(processedRequest, mv);

                        // 執(zhí)行 post 攔截器
            mappedHandler.applyPostHandle(processedRequest, response, mv);
        }
        catch (Exception ex) {
            dispatchException = ex;
        }
        catch (Throwable err) {
            // As of 4.3, we're processing Errors thrown from handler methods as well,
            // making them available for @ExceptionHandler methods and other scenarios.
            dispatchException = new NestedServletException("Handler dispatch failed", err);
        }
        //  渲染 view,返回結果 
        processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    }
    catch (Exception ex) {
        triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
    }
    catch (Throwable err) {
        triggerAfterCompletion(processedRequest, response, mappedHandler,
                new NestedServletException("Handler processing failed", err));
    }
    finally {
        if (asyncManager.isConcurrentHandlingStarted()) {
            // Instead of postHandle and afterCompletion
            if (mappedHandler != null) {
                mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
            }
        }
        else {
            // Clean up any resources used by a multipart request.
            if (multipartRequestParsed) {
                cleanupMultipart(processedRequest);
            }
        }
    }
}

簡單的說:找 handler朋魔、找 adaptor岖研、執(zhí)行 pre 攔截器、調用 handler 返回 modelAndView、執(zhí)行 post 攔截器孙援、渲染 view害淤。

springmvc.png

(1) 客戶端通過url發(fā)送請求

(2-3) DispatcherServlet 接收到請求,通過 HandlerMapping 到對應的handler拓售,并將 URI 映射的控制器 controller 組成處理器執(zhí)行鏈返回給 Dispatcher Servlet窥摄。

(4) 找 HandlerAdapter

(5-7)由找到的 HandlerAdapter 調用相應的 Handler 進行處理并返回 ModelAndView 給 DispatcherServlet

(8-9)DispatcherServlet 將獲取的 ModelAndView 傳遞給視圖解析器解析,返回具體 View

(10)DispatcherServlet 對 View 進行渲染視圖(即將模型數據填充至視圖中)

(11)將頁面響應給用戶

組件:

  • DispatcherServlet:前端控制器
    用戶請求到達前端控制器础淤,它就相當于mvc模式中的c崭放,DispatcherServlet 是整個流程控制的中心,由它調用其它組件處理用戶的請求鸽凶,DispatcherServlet 的存在降低了組件之間的耦合性币砂。

  • HandlerMapping:處理器映射器
       HandlerMapping 負責根據用戶請求 URL 找到 Handler 即處理器,Spring MVC 提供了不同的映射器實現不同的映射方式玻侥,例如:配置文件方式决摧,實現接口方式,注解方式等使碾。

  • Handler:處理器
       Handler 是繼 DispatcherServlet 前端控制器的后端控制器蜜徽,在 DispatcherServlet的控制下Handler對具體的用戶請求進行處理。由于 Handler 涉及到具體的用戶業(yè)務請求票摇,所以一般情況需要程序員根據業(yè)務需求開發(fā) Handler拘鞋。

  • HandlerAdapter:處理器適配器
      通過 HandlerAdapter 對處理器進行執(zhí)行,這是適配器模式的應用矢门,通過擴展適配器可以對更多類型的處理器進行執(zhí)行盆色。

  • ViewResolver:視圖解析器
      View Resolver 負責將處理結果生成 View 視圖,View Resolver首先根據邏輯視圖名解析成物理視圖名即具體的頁面地址祟剔,再生成 View 視圖對象隔躲,最后對 View 進行渲染將處理結果通過頁面展示給用戶。

  • View:視圖
      springmvc框架提供了很多的View視圖類型的支持物延,包括:jstlView宣旱、freemarkerView、pdfView等叛薯。我們最常用的視圖就是jsp浑吟。

一般情況下需要通過頁面標簽或頁面模版技術將模型數據通過頁面展示給用戶,需要由程序員根據業(yè)務需求開發(fā)具體的頁面耗溜。

3组力、HashMap 先擴容還是先轉紅黑樹。

static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
static final int TREEIFY_THRESHOLD = 8;
static final int MIN_TREEIFY_CAPACITY = 64;
static final float DEFAULT_LOAD_FACTOR = 0.75f;

初始化桶大小16抖拴,轉紅黑樹有兩個條件燎字,一個是沖突的 key 超過8個,并且桶的數量大于等于64。0.75是負載因子候衍,當前有0.75的桶都有值了笼蛛,就會進行擴容,擴大為當前的2倍脱柱,再進行 reHash伐弹。

所以對于這道題,判斷沖突的key大于等于8個時榨为,嘗試轉紅黑樹,如果桶的數量小于64煌茴,則擴容随闺;否則轉紅黑樹。

 for (int binCount = 0; ; ++binCount) {
         if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
             treeifyBin(tab, hash);
         break;
 }

binCount 從 0 開始的蔓腐,所以要減 1矩乐。

 final void treeifyBin(Node<K,V>[] tab, int hash) {
    int n, index; Node<K,V> e;
    if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
        resize();
    else if ((e = tab[index = (n - 1) & hash]) != null) {
        TreeNode<K,V> hd = null, tl = null;
        do {
            TreeNode<K,V> p = replacementTreeNode(e, null);
            if (tl == null)
                hd = p;
            else {
                p.prev = tl;
                tl.next = p;
            }
            tl = p;
        } while ((e = e.next) != null);
        if ((tab[index] = hd) != null)
            hd.treeify(tab);
    }
}

這是轉紅黑樹的方法,先判斷桶的大小回论,小于 64 就擴容散罕。

4、@Controller 與 @RestController

@RestController 注解相當于@ResponseBody + @Controller合在一起的作用傀蓉。

  1. 如果只是使用 @RestController 注解 Controller欧漱,則 Controller 中的方法無法返回 jsp 頁面,或者 html葬燎,在上面 Spring MVC 調用過程中 adapter 調用 handler 的時候 modelAndView 就會返回 null误甚,直接把 return 的內容放到 response 里了。

  2. 如果需要返回到指定頁面谱净,則需要用 @Controller配合視圖解析器InternalResourceViewResolver才行窑邦。
    如果需要返回JSON,XML或自定義mediaType內容到頁面壕探,則需要在對應的方法上加上@ResponseBody注解冈钦。

5、Spring Cloud 有哪些組件李请?
Eureka
Ribbon
Feign
Config
Hystrix
Hystrix DashBoard
Bus
Data Stream
6瞧筛、JVM 內存模型
不要答成運行時數據區(qū)域了。
內存模型

下面這個是運行時數據區(qū)域:
虛擬機

jvm.png

7捻艳、ConcurrentHashMap
ConcurrentHashMap

ConcurrentHashMap 和 HashMap 實現上類似驾窟,最主要的差別是 ConcurrentHashMap 采用了分段鎖(Segment),每個分段鎖維護著幾個桶(HashEntry)认轨,多個線程可以同時訪問不同分段鎖上的桶绅络,從而使其并發(fā)度更高(并發(fā)度就是 Segment 的個數)。
1.8 采用 CAS。

8恩急、Mysql 查詢優(yōu)化
EXPLAIN

9杉畜、InnoDB 與 MyISAM 的區(qū)別。
對 MyISAM 不是很了解衷恭。
主要區(qū)別是 MyISAM 不支持事務此叠。
MyISAM

10、volatile 有什么作用随珠,是不是原子性灭袁?
保證可見性: 修飾變量使其修改之后能夠立馬被其他線程看見。原理是 volatile 修飾的變量讀取時必須從主存中獲取窗看,修改后要立馬寫入主存茸歧,從而保證了修改之后能夠立馬被其他線程看見。
保證有序性:防止編譯器重排显沈。會加入一個內存屏障软瞎,防止后面的執(zhí)行排到前面。
不保證原子性:單一的讀/寫是具備原子性的拉讯,復合操作涤浇,比如 i++ 不具備原子性。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末魔慷,一起剝皮案震驚了整個濱河市只锭,隨后出現的幾起案子,更是在濱河造成了極大的恐慌盖彭,老刑警劉巖纹烹,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異召边,居然都是意外死亡铺呵,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門隧熙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來片挂,“玉大人,你說我怎么就攤上這事贞盯∫裟睿” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵躏敢,是天一觀的道長闷愤。 經常有香客問我,道長件余,這世上最難降的妖魔是什么讥脐? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任遭居,我火速辦了婚禮,結果婚禮上旬渠,老公的妹妹穿的比我還像新娘俱萍。我一直安慰自己,他們只是感情好告丢,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布枪蘑。 她就那樣靜靜地躺著,像睡著了一般岖免。 火紅的嫁衣襯著肌膚如雪岳颇。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天颅湘,我揣著相機與錄音赦役,去河邊找鬼。 笑死栅炒,一個胖子當著我的面吹牛,可吹牛的內容都是我干的术羔。 我是一名探鬼主播赢赊,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼级历!你這毒婦竟也來了释移?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤寥殖,失蹤者是張志新(化名)和其女友劉穎玩讳,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體嚼贡,經...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡熏纯,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了粤策。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片樟澜。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖叮盘,靈堂內的尸體忽然破棺而出秩贰,到底是詐尸還是另有隱情,我是刑警寧澤柔吼,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布毒费,位于F島的核電站,受9級特大地震影響愈魏,放射性物質發(fā)生泄漏觅玻。R本人自食惡果不足惜想际,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望串塑。 院中可真熱鬧沼琉,春花似錦、人聲如沸桩匪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽傻昙。三九已至闺骚,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間妆档,已是汗流浹背僻爽。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留贾惦,地道東北人胸梆。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像须板,于是被迫代替她去往敵國和親碰镜。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內容