網(wǎng)易的Java服務(wù)端技術(shù)面總結(jié)

???????說下這次面試的過程:獵頭先聯(lián)系我問我有沒有去網(wǎng)易面試的意向,我本著想混混面試經(jīng)驗的目的就答應(yīng)下來了侄刽。獵頭聯(lián)系我的第3天指黎,網(wǎng)易就安排了第一次技術(shù)面。面試是遠程進行的州丹,耗時1個半小時醋安。下面來分析下技術(shù)面一面的內(nèi)容(部分問題忘記了,這里列出我有印象的):

面試官的問題:

  1. ArrayList的結(jié)構(gòu)是怎么樣的?如何保證在擴容數(shù)組時保證高效率茬故?如果考慮擴容 add的時間復(fù)雜度是多少盖灸?
  2. HashMap的結(jié)構(gòu)是怎么樣的?除了數(shù)組加鏈表(紅黑樹)這種結(jié)構(gòu)磺芭,還有沒有其他結(jié)構(gòu)的HashMap(這個問題我記得不是很清楚赁炎,有可能問的是還有沒有其他結(jié)構(gòu)的Map)?
  3. List<? super T>钾腺、List<? extend T>徙垫、Enum<E extend Enum<E>>三種泛型的區(qū)別。1放棒、2里面可以加什么類型的對象姻报,取出的對象類型是什么?
  4. Java有哪些原生線程池间螟?構(gòu)建這些線程池傳的參數(shù)都有什么吴旋?這些參數(shù)作用是什么?
  5. 類是如何被加載的厢破?ClassLoader是怎么工作的荣瑟?一個class能否被兩個不同的ClassLoader加載?
  6. 說一下你最近做過的一個大功能摩泪。

題目解說:

???????網(wǎng)易的技術(shù)一面試題都并不難笆焰,考的比較基礎(chǔ)而且實在。主要是圍繞候選人基礎(chǔ)知識的方向去考见坑,沒有太多很偏很難的問題嚷掠。如果想要回答好這些題,并且給面試官留下好的印象荞驴。那么就不能在回答的時候僅僅就問題本身作答不皆,要回答的有深度并且擴展更多自己有把握的知識點,比如:說出問題背后知識的原理和設(shè)計哲學(xué)熊楼;說出自己使用的經(jīng)驗和心得粟焊,我這里只對問題本身做一些知識背景介紹,各位可以思考一下當你面對這些問題時孙蒙,什么樣的答案才是讓你自己滿意的答案项棠。

  1. ArrayList(面試老搭檔了)

    • 底層是用數(shù)組來保存有序數(shù)據(jù)的,每一次add都先判斷數(shù)組長度是否足夠挎峦,如果數(shù)組長度不夠就擴容香追,然后往當前位置的后一位插入數(shù)據(jù)。remove的過程并不會縮小數(shù)據(jù)組的長度坦胶,如果remove的位置后面還有數(shù)據(jù)透典,就把后面的數(shù)據(jù)復(fù)制前一位晴楔,然后把最后一位置空。
    • 先創(chuàng)建一個擴容后長度的數(shù)組峭咒,然后用System.arraycopy方法來對數(shù)據(jù)對象進行淺復(fù)制税弃,最終得到擴容后的數(shù)組
    • 我們基本可以把每次擴容看作是數(shù)組長度翻一倍,這樣的話add的時間復(fù)雜度就是log2
  2. HashMap(面試老搭檔了)

    • 結(jié)構(gòu):數(shù)組加鏈表的形式凑队,key的hash值決定這個鍵值對在數(shù)組中的位置则果,如果出現(xiàn)位置重復(fù)(碰撞),那么該位置就會以鏈表(或紅黑樹)的結(jié)構(gòu)存多個值漩氨。
    • 還有沒有其他結(jié)構(gòu)的Map:樹+鏈表的形式也可以西壮。理論上只要能通過key快速定位鍵值對在這個結(jié)構(gòu)中的位置就行,樹結(jié)構(gòu)就是在樹中搜索key所在位置找到鍵值對叫惊。
  3. 泛型(泛型加上類的繼承款青、接口實現(xiàn),能有效擴大泛型的使用場景)

    • List<? super T>:能添加的元素是T或者以T為父類的對象(添加的任意元素能夠直接轉(zhuǎn)化成T的任何一個超類)霍狰,取出來的對象為Object類型抡草。含義:Lits泛型接受T,或者其父類之中包含T的對象(有多重繼承的只要父類鏈條中包含T即可)蔗坯。List<? super T>是被設(shè)計用來添加數(shù)據(jù)的泛型康震,并且只能添加T類型或其子類類型的元素。下面的代碼使得這一點更容易理解步悠。
        class Car {}
    
        class Bus extends Car {}
    
        void genSuperTest() {
           List<? super Car> carList = new ArrayList<>();
           List<? super Bus> busList = new ArrayList<>();
    
           fatherList.add(new Car()); // 編譯通過
           fatherList.add(new Bus()); // 編譯通過签杈,Bus的直接父類是Car(Bus能轉(zhuǎn)成Car)瘫镇,所以能夠加進List<? super Car>里面
    
           sonList.add(new Car()); // 編譯錯誤 - Car不能轉(zhuǎn)成Bus對象
           sonList.add(new Bus()); // 編譯通過
        }
    
        void test(List<? super Bus> list) {
           Object obj = list.get(0); // 編譯通過鼎兽,注意這里取出來的對象被抹除為Object類型了
        }
    
    • List<? extend T>:無法往這個list中add對象,這里為什么不能add對象也是一個考點 ———— List<? extend T>要滿足隊列中任意元素都是T的一個子類铣除,也就是不能存在既有A又有B的情況(A和B都是T的子類)谚咬。并且取出的對象類型是T。List<? extends T>是被設(shè)計用來讀取數(shù)據(jù)的泛型尚粘,并且讀取類型為T择卦。
       private static void genExtendTest() {
          List<? extends Car> fatherList = new ArrayList<>();
          List<? extends Bus> sonList = new ArrayList<>();
    
          fatherList.add(new Car()); // 編譯錯誤,無法往List<? extend T>中add對象
          fatherList.add(new Bus()); // 編譯錯誤郎嫁,無法往List<? extend T>中add對象
    
          sonList.add(new Car()); // 編譯錯誤秉继,無法往List<? extend T>中add對象
          sonList.add(new Bus()); // 編譯錯誤,無法往List<? extend T>中add對象
       }
    
       private static void test(List<? extends Bus> list) {
          Bus bus = list.get(0); // 編譯通過泽铛,并且取出來的對象就是Bus
       }
    

    關(guān)于List<? super T>和List<? extend T>更多信息可以看:https://blog.csdn.net/qq_33591903/article/details/82746794

  4. Java原生線程池(下面這個四個是原生線程池):一開始我所理解的Java原生線程池就是java.util.concurrent.Executors中幾個公開的靜態(tài)方法生成的線程池尚辑。所以我就簡單說了一下這個幾個線程池的內(nèi)容(簡單介紹和用途):

    • FixedThreadPool:固定線程數(shù)量的線程池,線程池中線程數(shù)量不會超過用戶指定的線程數(shù)量盔腔。任務(wù)隊列最大長度:Integer.MAX_VALUE(注意避免OOM)杠茬。實現(xiàn)類是:ThreadPoolExecutor月褥;
    • SingleThreadExecutor:單線程的線程池,線程池中最多只會存在一個線程瓢喉。任務(wù)隊列最大長度:Integer.MAX_VALUE(注意避免OOM)宁赤。實現(xiàn)類是:ThreadPoolExecutor
    • CachedThreadPool:可緩存線程的線程池栓票。如果線程池空閑决左,會按照一定策略回收空閑線程(空閑線程存活時間為60s)。當線程池中沒有空閑線程時逗载,它會創(chuàng)建一個新線程來執(zhí)行新任務(wù)(不會進入任務(wù)隊列等待執(zhí)行)哆窿。實現(xiàn)類是:ThreadPoolExecutor
    • ScheduledThreadPoolExecutor:支持定時任務(wù)和周期任務(wù)的線程池厉斟。線程池中線程數(shù)量不會超過用戶指定的線程數(shù)量挚躯。實現(xiàn)類是:ScheduledThreadPoolExecutor
      關(guān)于Java有哪些原生線程池的問題擦秽,我在面試期間的回答主要是上面這些码荔。但是面試之后我回顧這個知識點的時候發(fā)現(xiàn),我的回答可能并不是面試官想要的答案感挥。上面這些線程池講到底都是ThreadPoolExecutor缩搅,只不過是不同的策略。FixedThreadPool; SingleThreadExecutor; CachedThreadPool在線程創(chuàng)建和任務(wù)執(zhí)行上機理都是一樣的触幼。
      如果從更深層次考慮硼瓣,我認為回答:ForkJoinPool; ScheduledExecutorService; ThreadPoolExecutor會更合理。下面是對這三個線程池實現(xiàn)類的介紹:
    • ForkJoinPool:該線程池的實現(xiàn)機制就是將大任務(wù)拆成多個小任務(wù)(fork過程)置谦,然后再將多個小任務(wù)處理結(jié)果匯總得到最終的結(jié)果(join過程)堂鲤。就是分治的思想,提供一個線程池來解決大規(guī)模的計算問題媒峡;
    • ScheduledExecutorService:這個線程池時在ThreadPoolExecutor的基礎(chǔ)上瘟栖,添加了定時任務(wù)和周期任務(wù)執(zhí)行的功能;
    • ThreadPoolExecutor:常用線程池谅阿;
      下圖是java原生線程池的接口半哟、類實現(xiàn)的繼承圖:
      image.png

關(guān)于線程池再推薦一篇文章:https://tech.meituan.com/2020/04/02/java-pooling-pratice-in-meituan.html 里面對線程池進行了系統(tǒng)全面的講解。

  1. 類的加載(你寫的代碼到JVM執(zhí)行的流程):
    • 類是如何被加載的:
      1. 編譯:先是編譯器將源碼文件(一般是xxx.java文件)編譯成.class文件签餐,在編譯器中完成寓涨;
      2. 加載:將.class文件加載到內(nèi)存中氯檐,在JVM中完成戒良;
      3. 驗證:驗證加載的.class文件是否符合虛擬機規(guī)范(這一步一般的編譯器也會做,但是虛擬機要保證正確性)男摧,在JVM中完成拇颅;
      4. 準備:為該類分配內(nèi)存(靜態(tài)變量占的空間等等),在JVM中完成搪缨;
      5. 解析:解析類副编、方法、字段名為引用(調(diào)用方法的時候通過引用來調(diào)用)流强,在JVM中完成痹届;
      6. 初始化:靜態(tài)變量賦值、static模塊執(zhí)行打月,在JVM中完成队腐;
    • ClassLoader是怎么工作的:這里我通過源碼來解釋:
      protected Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException {
          Class<?> clazz = findLoadedClass(className); // 1. 判斷自己這個ClassLoader是否已加載了這個class
          if (clazz == null) {
              ClassNotFoundException suppressed = null;
              try {
                  clazz = parent.loadClass(className, false); // 2. 委托自己的父加載器加載
              } catch (ClassNotFoundException e) {
                  suppressed = e;
              }
              if (clazz == null) {
                  try {
                      clazz = findClass(className); // 3. 自己的父加載器都沒有加載到,就自己加載
                  } catch (ClassNotFoundException e) {
                      e.addSuppressed(suppressed);
                      throw e;
                  }
              }
          }
          return clazz;
      }
      
    • 一個class能否被兩個不同的ClassLoader加載(這個知識點就涉及到我的知識盲區(qū)了):答案是可以奏篙。JVM在判定兩個class是否相同時柴淘,不僅要判斷兩個類名是否相同,而且要判斷是否由同一個類加載器實例(ClassLoader對象)加載的秘通。只有兩者同時滿足的情況下为严,JVM才認為這兩個class是相同的。
      下面這段是驗證代碼(需要用到第三方包:com.itranswarp:compiler:1.0):
        public class ClassLoaderTest {
           static final String JAVA_SOURCE_CODE = "package com.test; public class Test {}";
    
           @Test
           public void test() throws Exception {
              JavaStringCompiler compiler = new JavaStringCompiler();
              // 將源碼解析為二進制流充易,以供ClassLoader加載(同一份源碼梗脾,轉(zhuǎn)換出來的二進制流是一樣的)
              Map<String, byte[]> results = compiler.compile("Test.java", JAVA_SOURCE_CODE);
              // 自定義的classLoader加載class
              Class<?> clazz = compiler.loadClass("com.test.Test", results);
    
              JavaStringCompiler compiler1 = new JavaStringCompiler();
              // clazz和clazz1是由不同的ClassLoader對象加載出來的
              Class<?> clazz1 = compiler1.loadClass("com.test.Test", results);
              
              assertNotEquals(clazz, clazz1);
              assertNotEquals(clazz.newInstance().getClass(), clazz1.newInstance().getClass());
           }
        }
    
  2. 根據(jù)自己實際情況說明荸型。建議不要投機取巧盹靴,把自己明明沒有參與的功能說成是自己完成的。

個人總結(jié):

???????這次面試還是比較順利的瑞妇,題目難度比較低不過面試官喜歡深挖稿静,有幾次甚至問到很偏的源碼實現(xiàn)。因為疫情還沒有徹底結(jié)束辕狰,所以采用的是遠程的方式改备。

個人對面試的兩點建議:

  • 如果想面試成功一家行業(yè)內(nèi)頂尖的公司,我能給出的最好的建議就是:自己水平一定要達到這家公司的層次蔓倍,現(xiàn)在的面試內(nèi)卷程度已經(jīng)不是幾年前了悬钳,沒有真本事很難通過盐捷。
  • 老生常談的問題 —— 就算沒有換工作的意向我也建議一年參加有幾次面試,這對自己保持危機意識有很大的幫助默勾。在一家公司穩(wěn)定工作太久碉渡,安逸的生活很容易讓自己忘掉互聯(lián)網(wǎng)的殘酷。面試尤其是大公司的面試是我能想到成本最低母剥、收益最高的讓自己保持危機意識的方法了滞诺。

    最后吐槽一下:遠程面試真的很別扭。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末环疼,一起剝皮案震驚了整個濱河市习霹,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌炫隶,老刑警劉巖淋叶,帶你破解...
    沈念sama閱讀 221,576評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異伪阶,居然都是意外死亡爸吮,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評論 3 399
  • 文/潘曉璐 我一進店門望门,熙熙樓的掌柜王于貴愁眉苦臉地迎上來形娇,“玉大人,你說我怎么就攤上這事筹误⊥┰纾” “怎么了?”我有些...
    開封第一講書人閱讀 168,017評論 0 360
  • 文/不壞的土叔 我叫張陵厨剪,是天一觀的道長哄酝。 經(jīng)常有香客問我,道長祷膳,這世上最難降的妖魔是什么陶衅? 我笑而不...
    開封第一講書人閱讀 59,626評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮直晨,結(jié)果婚禮上搀军,老公的妹妹穿的比我還像新娘。我一直安慰自己勇皇,他們只是感情好罩句,可當我...
    茶點故事閱讀 68,625評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著敛摘,像睡著了一般门烂。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,255評論 1 308
  • 那天屯远,我揣著相機與錄音蔓姚,去河邊找鬼。 笑死慨丐,一個胖子當著我的面吹牛赂乐,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播咖气,決...
    沈念sama閱讀 40,825評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼挨措,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了崩溪?” 一聲冷哼從身側(cè)響起浅役,我...
    開封第一講書人閱讀 39,729評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎伶唯,沒想到半個月后觉既,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,271評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡乳幸,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,363評論 3 340
  • 正文 我和宋清朗相戀三年瞪讼,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片粹断。...
    茶點故事閱讀 40,498評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡符欠,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出瓶埋,到底是詐尸還是另有隱情希柿,我是刑警寧澤,帶...
    沈念sama閱讀 36,183評論 5 350
  • 正文 年R本政府宣布养筒,位于F島的核電站曾撤,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏晕粪。R本人自食惡果不足惜挤悉,卻給世界環(huán)境...
    茶點故事閱讀 41,867評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望巫湘。 院中可真熱鬧装悲,春花似錦、人聲如沸剩膘。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,338評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽怠褐。三九已至,卻和暖如春您宪,著一層夾襖步出監(jiān)牢的瞬間奈懒,已是汗流浹背奠涌。 一陣腳步聲響...
    開封第一講書人閱讀 33,458評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留磷杏,地道東北人溜畅。 一個月前我還...
    沈念sama閱讀 48,906評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像极祸,于是被迫代替她去往敵國和親慈格。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,507評論 2 359

推薦閱讀更多精彩內(nèi)容