1. 程式人生 > >java網際網路開發 史上最細最用心的知識點總結(面試必備)

java網際網路開發 史上最細最用心的知識點總結(面試必備)

     博主之前在鄭州上班,3年開發經驗,後來打算去帝都發展,但是這幾年由於鄭州所用技術和北京所要求的還是有差距的(二線城市技術相對來說要落後個3-5年吧),所以白天求生存晚上求發展,利用晚上和週末的時間去學習近幾年比較前沿的技術。

    經過1年左右的準備(博主是從java基礎開始又複習了一遍)確實技術水平提升了不少,後來為了準備面試在網上搜索網際網路相關的面試題,(我之前是做傳統行業的開發,現在想往網際網路方向發展)。終於找到一套知識點涵蓋比較全的面試題,但是美中不足的就是這套面試題只有面試相關知識的提問點而沒有對應的答案,無奈只能自己在網上找對應的答案。有時候一個面試題可能要花費博主將近2個小時的時間(先在網上找相關的部落格,然後經過一番研究之後根據自己的理解把其中的精髓用自己的話簡要的總結出來)。因此很多答案都是比較長的,因為可能一個答案會來自好幾個人的帖子內容或自己的理解。因此這些答案比較適合去深入理解這個知識點,而不是作為死記硬背的內容。其實還是挺慶幸沒有答案的,因為在自己總結整理答案的過程中,可以讓自己對於這些知識點有更深一步的理解。

    最後,博主終於在今年年初的時候如願在帝都找到了一份網際網路開發的工作(面試第二天就拿到了2個offer)。現在真的很感謝曾經努力的自己。現在博主把整理的這份知識點分享出來,希望可以幫助更多有需要的人,內容涵蓋Java基礎、常用框架、多執行緒、網路通訊、Linux、資料庫(MySql)、設計模式、演算法、快取、學習中遇到問題彙總十大部分。

    這份文件最初是在word裡邊整理的,很多我認為重要的地方都加粗和字型標紅了,但是當我整體複製到CSDN儲存之後不知道為什麼字型格式都變成黑白的了。由於內容太多我也就不一一加粗和字型標紅了,畢竟這是根據博主自己對知識點的理解去加粗和字型標紅的,畢竟每個人對同一個知識點的理解也都不一樣(一千個人心中就有一千個哈姆雷特),所以就黑白將就吧(哈哈)。如果確實想要我標註的版本的話(重要的地方字型加粗和標紅了),在本篇部落格評論區留下您的郵箱地址,我會抽時間統一發送的!

    本篇部落格會不定期更新,後邊我會陸續加入(spring boot、spring cloud、Zookeeper、Kafka、Elasticsearch 、RabbitMQ、Jenkins、Docker等技術)的相關知識點總結。另外歡迎大家轉載,但是請註明出處,這樣方便我給其他有需要的朋友傳送word版本的資料。

下邊還是放一張word版的效果圖吧


一、Java基礎

1.String類為什麼是final的。

1.設計需求

java設計者不希望使用者定義類去繼承String類,所以定義為final型別。final修飾類時,類不可被繼承;修飾變數,變數的值不可以被修改;修飾方法,方法不可被子類重寫。做這樣的規則規定,為了程式碼更嚴謹

2.效能需求

String類中的成員屬性也幾乎都設計成了private final的,這樣String就被設計成一個不變類,這樣有助於共享,提高效能。可以將字串物件儲存在字串常量池中以供與字面值相同字串物件共享。如果String物件是可變的,那就不能這樣共享,因為一旦對某一個String型別變數引用的物件值改變,將同時改變一起共享字串物件的其他String型別變數所引用的物件的值。

3.安全方面的考慮

Java設計出於安全性的考慮,不變的資料對於執行緒安全是有用的

執行緒安全基本型別傳值物件傳引用,記住這一點。既然傳引用,兩個變數就有可能指向同一個String。而在String可變情況下,我要是通過一個變數來更改String,那麼另一個變數取到的String也就變了!為什麼?因為兩個變數指向同個String。試想在多執行緒裡,這會是多麼可怕的一件事情:一個執行緒正在處理一個String,發現自己處理的String竟然變了

2.HashMap的原始碼,實現原理,底層結構。

HashMap實現原理

HashMap的主幹是一個Entry陣列。EntryHashMap的基本組成單元,每一個Entry包含一個key-value鍵值對。

 

 

底層結構如下圖:

 

簡單來說,HashMap由陣列+連結串列組成的,陣列是HashMap的主體,連結串列則是主要為了解決雜湊衝突而存在的

如果定位到的陣列位置不含連結串列(當前entrynext指向null,那麼對於查詢,新增等操作很快,僅需一次定址即可

如果定位到的陣列包含連結串列,對於新增操作,其時間複雜度依然為O(1),因為最新的Entry會插入連結串列頭部,急需要簡單改變引用鏈即可,而對於查詢操作來講,此時就需要遍歷連結串列,然後通過傳入key與陣列中key物件的hash值和equals方法逐一比對查詢,同時成立時完成匹配(具體如下圖紅色標記)。所以,效能考慮,HashMap中的連結串列出現越少,效能才會越好。

 

remove刪除陣列下的連結串列時,只需改變連結串列物件entry內的next屬性引用即可。

儲存位置(雜湊表的索引)的確定流程是這樣的:

 

個人理解:hashmap中的putgetremove方法其實本質都是通過key找到雜湊表中的對應的物件entry,然後通過操作物件內的屬性value來實現hashmap的操作。

為何HashMap的陣列長度一定是2的次冪?

HashMap()一開始構造一個具有預設初始容量 (16) 和預設載入因子 (0.75) 的空 HashMap,當陣列中的元素大於16*0.75=12個的時候,陣列數量擴充套件為之前長度的2倍。之所以擴充套件2倍(只能擴充套件2倍)的原因是為了保證得到的新的陣列索引和老陣列索引一致(大大減少了之前已經雜湊良好的老陣列的資料位置重新調換),個人理解。

3.反射中,Class.forNameclassloader的區別

類的例項化與類的初始化是兩個完全不同的概念:

· new例項化物件如果類沒有進行過初始化,則需要先對其進行初始化

· 例項化:類的例項化是指建立一個類的例項(物件)的過程;

· 初始化:啟用類的靜態變數的初始化Java程式碼和靜態Java程式碼塊,並初始化程式設計師設定的變數值,是類生命週期中的一個階段。

Java類裝載過程

 

Class.forName(className)方法,內部呼叫的方法是 Class.forName(className,true,classloader);

2boolean引數表示類是否需要初始化,  Class.forName(className)預設是需要初始化。

一旦初始化,就會觸發目標物件的 static塊程式碼執行static引數也也會被再次初始化。

ClassLoader.loadClass(className)方法,內部呼叫方法ClassLoader.loadClass(className,false);

2boolean引數,表示目標物件是否進行連結,false表示不進行連結,由上面介紹可以,不進行連結意味著不進行包括初始化等一些列步驟,那麼靜態塊和靜態物件就不會得到執行

一般情況下,這兩個方法效果一樣,都能裝載Class

但如果程式依賴於Class是否被初始化,就必須用Class.forName(name)

舉例說明他們各自的使用方法
    java使用JDBC連線資料庫時候,我們首先需要載入資料庫驅動。
    Class.forName("com.mysql.jdbc.Driver");//通過這種方式將驅動註冊到驅動管理器上
    Connection conn = DriverManager.getConnection("url","userName","password");//通過驅動管理器獲得相應的連線
    檢視com.mysql.jdbc.Driver原始碼:

 

Class.forName("com.mysql.jdbc.Driver")方法以後,他會進行class的初始化,執行static程式碼塊。
    也就是說class初始化以後,就會將驅註冊到DriverManageer上,之後才能通過DriverManager去獲取相應的連線。
    但是要是我們使用ClassLoader.loadClass(com.mysql.jdbc.Driver)的話,不會link,更也不會初始化class
    相應的就不會回將Driver註冊到DriverManager上面,所以肯定不能通過DriverManager獲取相應的連線。

4.sessioncookie的區別和聯絡,session的生命週期,多個服務部署時session管理。

cookie session 的區別和聯絡

1cookie資料存放在客戶的瀏覽器上,session資料放在伺服器上session不是儲存在記憶體中,而是儲存在檔案或資料庫中

2cookie不是很安全,別人可以分析存放在本地的COOKIE並進行COOKIE欺騙
   考慮到安全應當使用session

3session會在一定時間內儲存在伺服器上。當訪問增多,會比較佔用你伺服器的效能
   考慮到減輕伺服器效能方面,應當使用COOKIE

4、單個cookie儲存的資料不能超過4K,很多瀏覽器都限制一個站點最多儲存20cookie

5session 的執行依賴 session id,而 session id 是存在 cookie 中的,也就是說,如果瀏覽器禁用了 cookie ,同時 session 也會失效(但是可以通過其它方式實現,比如在 url 中傳遞 session_id、表單隱藏域傳遞

6、所以個人建議:
   將登陸資訊等重要資訊存放為SESSION
   其他資訊如果需要保留,可以放在COOKIE

session的生命週期:

建立:Sessinon在使用者訪問第一次訪問伺服器時建立,需要注意只有訪問JSPServlet等程式時才會建立Session,只訪問HTMLIMAGE等靜態資源並不會建立Session,可呼叫request.getSession(true)強制生成Session

Session什麼時候失效?

1. 伺服器會把長時間沒有活動的Session從伺服器記憶體中清除,此時Session便失效。TomcatSession的預設失效時間為30分鐘。

2. 呼叫Sessioninvalidate方法。

Session對瀏覽器的要求:

 雖然Session儲存在伺服器,對客戶端是透明的,它的正常執行仍然需要客戶端瀏覽器的支援。這是因為Session需要使用Cookie作為識別標誌。HTTP協議是無狀態的,Session不能依據HTTP連線來判斷是否為同一客戶,因此伺服器向客戶端瀏覽器傳送一個名為JSESSIONIDCookie,它的值為該Sessionid(也就是HttpSession.getId()的返回值)。Session依據該Cookie來識別是否為同一使用者。

對於不支援Cookie解決方案:URL地址重寫

URL地址重寫是對客戶端不支援Cookie的解決方案。URL地址重寫的原理是將該使用者Sessionid資訊重寫到URL地址中。伺服器能夠解析重寫後的URL獲取Sessionid。這樣即使客戶端不支援Cookie,也可以使用Session來記錄使用者狀態。HttpServletResponse類提供了encodeURL(String url)實現URL地址重寫,該方法會自動判斷客戶端是否支援Cookie。如果客戶端支援Cookie,會將URL原封不動地輸出來。如果客戶端不支援Cookie,則會將使用者Sessionid重寫到URL中。

多個服務部署時session管理:

1.通過資料庫mysql共享session

a.採用一臺專門的mysql伺服器來儲存所有的session資訊。

      使用者訪問隨機的web伺服器時,會去這個專門的資料庫伺服器check一下session的情況,以達到session同步的目的。

 缺點就是:依懶性太強,mysql伺服器無法工作,影響整個系統;

2.通過cookie共享session

   把使用者訪問頁面產生的session放到cookie裡面,就是以cookie為中轉站。

   當訪問伺服器A時,登入成功之後將產生的session資訊存放在cookie中;當訪問請求分配到伺服器B時,伺服器B先判斷伺服器有沒有這個session,如果沒有,在去看看客戶端的cookie裡面有沒有這個session,如果cookie裡面有,就把cookie裡面的sessoin同步到web伺服器B,這樣就可以實現session的同步了。

   缺點:cookie的安全性不高,容易偽造、客戶端禁止使用cookie等都可能造成無法共享session

3.通過memcache同步session

memcache可以做分散式,如果沒有這功能,他也不能用來做session同步。他可以把web伺服器中的記憶體組合起來,成為一個"記憶體池",不管是哪個伺服器產生的sessoin都可以放到這個"記憶體池"中,其他的都可以使用。

  優點:以這種方式來同步session,不會加大資料庫的負擔,並且安全性比用cookie大大的提高,把session放到記憶體裡面,比從檔案中讀取要快很多。

  缺點:memcache把記憶體分成很多種規格的儲存塊,有塊就有大小,這種方式也就決定了,memcache不能完全利用記憶體,會產生記憶體碎片,如果儲存塊不足,還會產生記憶體溢位。

4.通過redis共享session

redismemcache一樣,都是將資料放在記憶體中。區別的是redis會週期性的把更新的資料寫入磁碟或者把修改操作寫入追加的記錄檔案,並且在此基礎上實現了master-slave(主從)同步。支援持久化及key過期刪除策略

   根據實際開發應用,一般選擇使用memcacheredis方式來共享session.

5.Java中的佇列都有哪些,有什麼區別。

在併發程式設計中,一般推薦使用阻塞佇列,這樣實現可以儘量地避免程式出現意外的錯誤。

阻塞佇列與普通佇列的區別在於當佇列是空的時,從佇列中獲取元素的操作將會被阻塞,或者當佇列是滿時,往佇列裡新增元素的操作會被阻塞。試圖從空的阻塞佇列中獲取元素的執行緒將會被阻塞,直到其他的執行緒往空的佇列插入新的元素。同樣,試圖往已滿的阻塞佇列中新增新元素的執行緒同樣也會被阻塞,直到其他的執行緒使佇列重新變得空閒起來,如從佇列中移除一個或者多個元素,或者完全清空佇列

非阻塞佇列ConcurrentLinkedQueue):執行緒安全 

基於連結節點的、無界的、執行緒安全。此佇列按照 FIFO(先進先出)原則對元素進行排序。佇列的頭部是佇列中時間最長的元素。佇列的尾部是佇列中時間最短的元素。新的元素插入到佇列的尾部,佇列檢索操作從佇列頭部獲得元素。當許多執行緒共享訪問一個公共 collection 時,ConcurrentLinkedQueue 是一個恰當的選擇。此佇列不允許 null 元素。

阻塞佇列LinkedBlockingQueue:執行緒安全

FIFO(先進先出)排序元素。佇列的頭部是在佇列中時間最長的元素。佇列的尾部是在佇列中時間最短的元素。新元素插入到佇列的尾部,並且佇列檢索操作會獲得位於佇列頭部的元素。連結佇列的吞吐量通常要高於基於陣列的佇列,但是在大多數併發應用程式中,其可預知的效能要低。

注意:

1、必須要使用take()方法在獲取的時候達成阻塞結果2、使用poll()方法將產生非阻塞效果

 

6.Java的記憶體模型以及GC演算法

Java記憶體模型(簡稱JMMJMM是隸屬於JVM)決定一個執行緒對共享變數的寫入何時對另一個執行緒可見。從抽象的角度來看,JMM定義了執行緒和主記憶體之間的抽象關係:執行緒之間的共享變數儲存在主記憶體(main memory)中,每個執行緒都有一個私有的本地記憶體(local memory),本地記憶體中儲存了該執行緒以讀/寫共享變數的副本

 

JVMJava記憶體模型的實現

對於一個物件的成員方法,這些方法中包含本地變數,仍需要儲存在棧區,即使它們所屬的物件在堆區。 對於一個物件的成員變數,不管它是原始型別還是包裝型別,都會被儲存到堆區。

Static型別的變數以及類本身相關資訊都會隨著類本身儲存在堆區。

堆中的物件可以被多執行緒共享。如果一個執行緒獲得一個物件的應用,它便可訪問這個物件的成員變數。如果兩個執行緒同時呼叫了同一個物件的同一個方法,那麼這兩個執行緒便可同時訪問這個物件的成員變數,但是對於本地變數,每個執行緒都會拷貝一份到自己的執行緒棧中。

下圖展示了上面描述的過程:

 

GC演算法:

回收哪些物件?GC主要進行回收的記憶體是JVM中的方法區
什麼時候回收?已死的物件(主要用可達性分析判斷一個物件是否還存在引用,如果該物件沒有任何引用就應該被回收。);


怎麼回收? 

標記 -清除演算法老年代常用):如它的名字一樣,演算法分為標記清除兩個階段:首先標記出所有需要回收的物件,在標記完成後統一回收掉所有被標記的物件。效率不高、產生記憶體碎片)

 

複製演算法新生代常用):它將可用記憶體按容量劃分為大小相等的兩塊,每次只使用其中的一塊。當這一塊的記憶體用完了,就將還存活著的物件複製到另外一塊上面,然後再把已使用過的記憶體空間一次清理掉。(簡單高效,但是會將記憶體縮小為原來的一半

 

標記-整理演算法老年代常用):標記過程仍然與標記-清除演算法一樣,但後續步驟不是直接對可回收物件進行清理,而是讓所有存活的物件都向一端移動,然後直接清理掉端邊界以外的記憶體

 

分代收集演算法分代收集Generational Collection)演算法,把Java堆分為新生代和老年代,這樣就可以根據各個年代的特點採用最適當的收集演算法。在新生代中,每次垃圾收集時都發現有大批物件死去,只有少量存活,那就選用複製演算法,只需要付出少量存活物件的複製成本就可以完成收集。而老年代中因為物件存活率高、沒有額外空間對它進行分配擔保,就必須使用標記-清理標記-整理演算法來進行回收。

垃圾收集器(垃圾收集器就是記憶體回收GC演算法的具體實現):

CMS收集器CMS收集器是一種以獲得最短停頓時間為目標的收集器。

G1收集器JDK1.7 Update 14之後的HotSpot虛擬機器正式提供了商用的G1收集器,與其他收集器相比,它具有如下優點:並行與併發;分代收集;空間整合(不會產生記憶體碎片)可預測的停頓等。

7.Java7Java8的新特性(baidu問的,BT)

Java7 新特性

1.switch中可以使用字串了

 2.運用List<String> tempList = new ArrayList<>();即泛型例項化型別自動推斷

3.語法上支援集合,而不一定是陣列

final List<Integer> list = [1,2,3,4,5,6]

4.新增一些取環境資訊的工具方法

 

Java8新特性

1.Java 8允許我們給介面新增一個非抽象的方法實現,只需要使用 default關鍵字即可,這個特徵又叫做擴充套件方法,示例如下:

 

 2.lambda表示式

3.函式式介面

8.Java陣列和連結串列兩種結構的操作效率,在哪些情況下(從開頭開始,從結尾開始,從中間開始),哪些操作(插入,查詢,刪除)的效率高

總結:

1、存取方式上,陣列可以順序存取或者隨機存取,而連結串列只能順序存取; 

2、儲存位置上,陣列邏輯上相鄰的元素在物理儲存位置上也相鄰,而連結串列不一定; 

3、儲存空間上,連結串列由於帶有指標域,儲存密度不如陣列大; 

4、按序號查詢時,陣列可以隨機訪問,時間複雜度為O(1),而連結串列不支援隨機訪問,平均需要O(n); 

5、按值查詢時,若陣列無序,陣列和連結串列時間複雜度均為O(1),但是當陣列有序時,可以採用折半查詢將時間複雜度降為O(logn); 

6、插入和刪除時,陣列平均需要移動n/2個元素,而連結串列只需修改指標即可; 

7、空間分配方面:
  陣列在靜態儲存分配情形下,儲存元素數量受限制,動態儲存分配情形下,雖然儲存空間可以擴充,但需要移動大量元素,導致操作效率降低,而且如果記憶體中沒有更大塊連續儲存空間將導致分配失敗; 
  連結串列儲存的節點空間只在需要的時候申請分配,只要記憶體中有空間就可以分配,操作比較靈活高效;

9.Java記憶體洩露的問題調查定位:jmapjstack的使用等等

二、框架

1.struts1struts2的區別

struts1是基於JSPservlet的一個開源的Web應用框架,使用的是MVC的設計模式

struts2是基於webwork技術的框架,是sunwebwork公司聯手開發的一個功能非常齊全的框架,struts2struts1沒有任何關係,是一個全新的框架 它吸收了struts1webwork的優勢

2.struts2springMVC的區別

 

3.spring框架中需要引用哪些jar包,以及這些jar包的用途

org.springframework.aop-3.0.6.RELEASE

Spring的面向切面程式設計,提供AOP(面向切面程式設計)實現

org.springframework.aspects- 3.0.6.RELEASE

Spring提供對AspectJ框架的整合

org.springframework.beans-3.0.6.RELEASE

SpringIoC(依賴注入)的基礎實現

org.springframework.core-3.0.6.RELEASE

Spring3.0.6的核心工具包

org.springframework.expression-3.0.6.RELEASE

Spring表示式語言

org.springframework.jdbc-3.0.6.RELEASE

JDBC的簡單封裝

org.springframework.orm-3.0.6.RELEASE

整合第三方的ORM框架,如hibernate,ibatis,jdo,以及 springJPA實現

4.srpingMVC的原理

1. 客戶端請求提交到DispatcherServlet

2. DispatcherServlet控制器查詢一個或多個HandlerMapping,找到處理請求的Controller

3. DispatcherServlet將請求提交到Controll