轉載請註明出處: 貼一貼個人後端開發面試題。本文是面試回寢室後憑記憶羅列出來的問題,大概90%的問題都在這裏面了,有幾個問題的實在是想不起來了= =,有些問題自我感受回答的很差,因此我是查了資料後從新整理了再貼上答案的。若有錯誤或不適合的,歡迎你們評論點出,謝謝!css
雖然面試的是Java實習生職位,但問題不侷限於Java語言。html
面試過程當中只有三個技術無關的話題:前端
這類的話題通常稍微準備一下,都不會有什麼問題。java
首先咱們會在web.xml
中註冊一個DispatcherServlet
,並令這個servlet
接收全部的請求,項目啓動後Spring會掃描配置文件,根據配置加載和實例化類,其中掃描到的帶有@Controller
或者@RestController
註解的類則是請求要映射到的類,Spring MVC掃描裏面全部和請求映射有關的註解, 如@RequestMapping
、@ResponseBody
、@RequestParam
等。當接收到一個請求時,它會根據請求的url映射到對應的controler,並根據返回值判斷是渲染jsp頁面仍是返回普通文本,亦或是返回json。
AOP是經過動態代理來實現的,有兩種經常使用的技術,一是JDK的動態代理
,二是CGLIB
,而不管是前者仍是後者,都是生成動態生成類的字節碼來實現的。JDK的動態代理只能處理接口實現的方法
,而CGLIB則沒有這個限制。由於字節碼是動態生成的,因此能夠在生成的字節碼當中,在目標方法先後插入定義好的方法的調用。
當在一個類、方法或者字段上標上註解後,能夠經過obj.getClass().isAnnotationPresent(..)
來判斷一個目標是否被特定的註解標識,經過obj.getClass().getAnnotation(..)
來獲取標誌是註解,以此得到註解上的信息。使用註解能夠幫助咱們在項目的編譯期或運行時給類、方法或對象添加一個額外的信息,給編程增長了很大的靈活性。好比用@Override
來標誌這是重寫父類的方法,那麼編譯器就能夠在編譯期檢查該方法是否真的是重寫父類的方法,將錯誤扼殺在編譯器。
線程有五種狀態:建立
、就緒
、運行
、阻塞
、死亡
。
調用start
方法時,線程就會進入就緒狀態。
在線程獲得cpu時間片
時進入運行狀態。
線程調用yield
方法可讓出cpu時間回到就緒狀態。
線程運行時可能因爲IO
、調用sleep
、wait
、join
方法或者沒法得到同步鎖
等緣由進入阻塞狀態。
當線程得到到等待的資源資源或者引發阻塞的條件獲得知足時(調用notify
或notifyAll
),會從阻塞狀態進入就緒狀態。
當線程的run
方法執行結束或者調用interrupt
方法時,線程就進入死亡狀態。
Java實現同步的方法有:linux
- 使用
synchronized
關鍵字爲方法或代碼塊加鎖。- 使用
volatile
修飾變量,可是volatile不保證原子性
。- 使用
ReentrantLock
或者ReentrantReadWriteLock
, 這種方法比synchronized
更靈活。- 使用
Semaphore
,容許最多n個線程同時訪問資源。
HashMap
與Hashtable
的區別。
HashMap
是線程不安全
的,Hashtable
是線程安全的。HashMap
的key和value接受null,Hashtable
不接受。HashMap
繼承自AbstractMap
,Hashtable
繼承自Directory
。
這裏我回答了最近正在看《深刻理解Java虛擬機》一書,本想着這方面的問題能答上一些的,沒想到面試官直接說
那看樣子還不是很瞭解,就不問這塊的問題了= =.. 心塞
可是我估摸着大概若是問的話會問:程序員
JVM的內存一共分爲5個部分:web
程序計數器
: 裏面存放着線程執行的指令。方法區
: 存放類的信息,如:類名、方法、成員變量等,也存放着常量池。虛擬機棧
: 存放着局部變量表、操做數棧、方法出口信息等方法執行所需信息。本地方法棧
: 存放程序調用native方法的信息。堆
: 這五個部分中最大的,對象的內存分配都是在堆內存中。
-Xmx
: 指定最大堆內存-Xms
: 指定初始化堆內存大小。-Xmn
: 指定年輕代內存初始內存大小,同時也是最大內存大小。-XX:NewSize
: 指定年輕代內存大小。-XX:NewRatio
: 指定年輕代和老年代的內存比例。-XX:MaxHeapSize
: 指定程序最大內存。-XX:+PrintGC
: 打印GC日誌。-XX:+PrintGCDetails
: 打印詳細的GC日誌。-Xloggc
: 打印GC日誌保存位置。
引用計數算法
:該算法對每個對象都有一個引用計數,沒增長一次引用就+1,減小一次引用-1,在回收時將引用計數爲0的對象清理掉。這種算法簡單,可是沒法解決循環引用的問題(好比: A引用B, B也引用A,可是A和B都沒有被其它任何對象引用)。
標記-清除算法
:該算法分爲兩個階段, 第一階段遍歷找出全部須要被回收的對象,並作上標記,第二階段對清理全部被標記的對象,這種算法效率比較低,而且會產生較多的內存碎片。
標記-整理算法
:該算法的第一階段和標記-清除算法是同樣的,而第二階段它不是直接清理掉垃圾對象,並且將存活的對象往同一側移動,移動完成後清理掉另外一側全部的對象。這種算法不會產生內存碎片,可是效率低下。
複製算法
:該算法將內存分爲兩個區域,進行垃圾回收時,就將還活着的對象複製到另外一塊內存區域中,而後再將整片內存區域清空。這種算法簡單快速,並且不會產生內存碎片,可是由於將內存分紅兩塊,因此可用的內存會少不少。
分代收集算法
:將內存細分爲多個區域,不一樣區域GC的頻率,並對不一樣的區域採用適當的收集算法。如JVM將內存分爲年輕代和老年代,普通對象最開始分配在年輕代(大對象會直接分配到老年代),同一個對象在通過幾回GC後還存活着,就認爲這個對象的生命週期會比較長,將其移入老年代,GC主要發生在年輕代。
Java中主要有Bootstrap類加載器
、ExtClassLoader
、AppClassLoader
,其中Bootstrap類加載器
主要加載JAVA_HOME/lib
目錄下的類庫,ExtClassLoader
加載JAVA_HOME/lib/ext
目錄下的類庫,AppClassLoader
加載classpath
指向目錄下的類庫。Java的類加載器使用
雙親委派模型
,除了頂層的Bootstrap類加載器
外,其他的類加載器都有父類加載器,當一個類加載器要加載一個類時,它不會直接去加載,而是委託父類加載器嘗試加載,父類加載器若是沒法完成,則繼續委託其父類加載器加載,若是在期間有某一個類加載器發現已經加載過這個類,則會將已經加載的類返回,子類再也不加載。若全部的類加載器都未加載過這個類,那麼最開始嘗試加載的加載器纔會去加載這個類。使用這樣的加載機制的好處是: 對於同一個類,如:java.lang.String
,能保證整個程序中都是使用的這一個類,不然若是用戶在本身的項目中也寫了一個java.lang.String
類,那麼項目中將存在兩個String類,一個是java提供的String類,一個是用戶自定義的String類,不只使項目變得混亂,並且不安全。面試
我我的由於只簡單接觸過而沒有實際應用過Hibernate
,因此沒能從比較好的角度來回答這個問題。redis
Hibernate
的優勢是它是一個徹底的ORM框架
,使用Hibernate
能夠作到不用手寫SQL,並且無須關心使用何種數據庫,可移植性較好,當須要更變數據庫時須要作的修改不多甚至爲0。其缺點是須要根據數據庫的設計在實體進行又一次的配置,且幫程序員作了太多事,若是須要進行調優的話須要對Hibernate
有比較深的瞭解。
MyBatis
的優缺點差很少和Hibernate
相反,咱們須要手寫SQL
語句和配置結果集和實體類的映射
,即便是簡單的單表操做也須要寫SQL(能夠經過攔截器
來實現CommonMapper,或者可使用生成器來生成代碼),所以MyBatis
要進行SQL調優也簡單直接。其次是MyBatis
的二級緩存
功能較弱,是針對namespace
的。
較常使用的方法是
explain SQL
查看執行計劃,根據查詢計劃能夠知道是否使用了索引
,是否進行來全表掃描
以及查詢的順序,依此咱們能夠創建適當的索引和鏈接查詢調優。
還有一個是開啓慢查詢記錄執行時間長的SQL語句。算法
- 一般會在
WHERE
、JOIN ON
和ORDER BY
使用到字段上加上索引。- 避免查詢時判斷
NULL
,不然可能會致使全表掃描。- 避免使用
OR
來鏈接查詢條件,不然可能致使全表掃描,能夠改用UNION
或UNION ALL
。- 避免
LIKE
查詢,不然可能致使全表掃描。- 不使用
SELECT *
,只查詢必須的字段,避免加載無用數據。- 能用
UNION ALL
的時候就不用UNION
,UNION
過濾重複數據要耗費更多的cpu資源。
由於平時都是用的InnoDB
,對其它引擎的瞭解甚少,因此這個問題沒答上= =,這裏直接貼一個連接好了。
相關連接: MySQL存儲引擎介紹
- 使用
$(..).css({..})
來改變元素的樣式。- 使用
$(..).attr(..)
改變元素的屬性。- 使用
$(..).html(..)
改變元素的html內容。- 使用
$(..).text(..)
改變元素的文本內容。- 使用
$(..).remove(..)
刪除元素。- 使用
$(..).append(..)
添加元素。
若是是使用JSP
等後端模板的話,通常會將須要分頁的JSP代碼
抽成一個單獨的JSP文件
,並在頁面中動態計算分頁按鈕的展現方式,在母頁中include
該JSP文件
,而後在前端點擊分頁按鈕時,經過AJAX
請求下一頁的內容,服務器端將渲染後的HTML
返回給前端,前端經過$(..).html()
等方式替換展現內容。
若是是在先後端分離的項目中,通常會使用一些前端的框架,如:React.js
、Vue.js
等,每次只向後臺請求分頁的數據,通常數據交互格式使用JSON
,並替換已有的數據,觸發頁面內容的改變。
RESTful
是無狀態的,採用URL
+HTTP請求方法
來描述資源
和行爲
。
通常在先後端分離的項目中,後端會提供REST接口
給前端,其HTTP請求方法
通常爲:
GET
: 獲取資源。POST
: 更新資源。PUT
: 建立資源。DELETE
: 刪除資源。其次,
RESTful
因爲是無狀態的,通常會採用JWT
或OAuth
的方式來認證一個用戶,Token
是保存在前端的,爲了安全性通常會配合HTTPS
使用。
HTTP請求
分爲三部分:請求行
、請求頭
、請求體
:
請求行
: 第一行是METHOD URL protocal
,如GET http://abc.com HTTP/1.1
。
請求頭
: 從第二行開始,每一行的內容都是一個請求頭參數值,直到遇到一個空行
爲止。
請求體
: 請求頭和請求體中間隔着一行空行
做爲分界,請求體包含着本次請求攜帶的內容。
GET
方式的請求沒有請求體,其是將參數追加到URL
後面,URL
中?
後面的內容爲請求參數。
POST
方式則三部分都有,且POST
的請求頭應當包含Content-Type
來指明請求體中內容的類型。
上傳文件的話會設置Content-Type
爲multipart/form-data
,並指定boundary
的值來標識請求體中內容的分界,而在請求體中,不一樣的內容(如:文件A和文件B)之間使用boundary
的值來標識分界,而且請求體中每部份內容都會有Content-Disposition
和Content-Type
來指明這部份內容的類型和信息。後端的話使用
ServletFileUpload
來解析請求,得到FileItem
的List
,遍歷Item
,而後經過Item
得到輸入流,從輸入流中讀取上傳文件的數據,再構建FileOutputStream
輸出到磁盤中保存。
若是使用Spring MVC
,則能夠在接收請求的方法中接收CommonsMultipartFile
,並使用transferTo
方法保存到磁盤中。
這個也沒答上來,平時都是使用jQuery
封裝的AJAX
或者其餘AJAX
框架。
AJAX是利用瀏覽器的AJAX引擎來實現的異步請求,經過XMLHttpRequest
對象來發送請求,由AJAX引擎向服務器發送和接收響應,再回調給用戶處理,達到不阻塞用戶界面和無刷新的目的。
資料來源: AJAX工做原理及其優缺點。
若是是查找二進制文件,可使用whereis
。
若是是查找命令,可使用which
。
若是是其餘文件,可使用find
命令(其實什麼均可以找),-name
指定搜索的名稱或者匹配串,-maxdepth
指定搜索的深度。
也可使用locate
命令查找,可是最新變更的文件可能會找不到,由於該命令其實是搜索數據庫,該數據庫天天自動更新,能夠手動執行updatedb
更新。
使用ps
命令能夠查看進程狀態,ps -ef
查看全部進程,配合grep
命令能夠進行篩選, 如查看tomcat
進程的命令是:ps -ef | grep tomcat
。
這題沒也沒答上= =
使用grep
命令能夠實現:
grep -rn /path/to/target/dir -e "pattern"
-r
: 遞歸
-n
: 顯示行數
-w
: 徹底匹配
例子:grep -rn. -e "ERROR"
輸出:./面試:143:輸出: ./面試:144:上面的命令搜索當前目錄及其子目錄中的文件,並輸出含有ERROR內容的行
詳細答案及來源: How to find all files containing specific text on Linux?
Redis
在我接觸過的項目中主要作了兩件事:
緩存
。存儲須要計算的信息
。
Redis
也能夠用來作消息訂閱
、隊列
等。
這個問題我估摸着面試官想問的是Redis
的數據保障的方法,否則崩潰了除了重啓還能怎麼辦?
Redis
有提供數據持久化的功能,一種是快照
,一種是AOF
。
快照
是在某一個時間點將全部數據寫入到磁盤中,AOF
是將被執行的命令複製到硬盤中,快照
的文件體積要比AOF
的文件體積小。前者在恢復時速度
比後者快,可是由於是間隔持久化
,因此會有必定量的數據丟失
。後者由於是實時寫入
的,因此數據的完整性比較好,若是丟失的話通常也就丟失一秒的數據。其次須要作主從複製,這樣一份數據能夠保存在多臺服務器上,且能夠避免
Redis
崩潰到重啓完成這段時間內沒法提供正常服務,同時從服務器能夠分擔主服務器的讀壓力。
沒配置過因此沒答上= =
相關鏈接: Redis集羣教程。
- 前一家公司實習的時候主要作什麼?
- 講一下作過的項目?
- 項目中有沒有遇到什麼難點?怎麼解決的?
- 有沒有作過什麼有亮點的東西?
其中在問題3根據個人回答,繼續將狀況複雜化讓我給出解決方案,一步一步問。
最後. 若是不是熟悉的技術真的不要往簡歷上寫= = 我由於在項目須要,學習過Android,可是項目完成後就
沒碰過了(近一年),把對Android有必定的瞭解寫上簡歷,結果問了三個問題就答不上了= =
雖然最終拿到了offer,可是由於各方面緣由,最後仍是放棄了,在此也提醒一下,秋招千萬不要錯過= =,拖到這個時候,好的實習的真很差找(成都)。
學習技術不能知其然而不知其因此然,往後不只會持續更新面試內容,同時本專欄會持續發佈Java
、數據庫
、Linux
、算法
等方面的學習文章。歡迎關注。
最後,若有錯誤或不適合的,請你們評論點出,共同進步,謝謝!