Java 程式設計師 面試前必備知識
前言
準備了接近兩個月的面試筆試,現在終於是可以休息下了。真真是應了那句老話“臺上一分鐘, 臺下十年功。”。
人嘛,越努力,才會越幸運。機會總是留給有準備的人的。
下面分享一下我的Java實習生準備所看過的材料,(雖然至今還有些依然看不懂地方。) 希望對這方面的同學有點幫助。
正文
自我介紹
先針對自己的情況寫段自我介紹,真實一些就好了,這方面我倒是沒有什麼其他的建議。我就寫了我自己的真實的情況,比如喜歡寫部落格,喜歡學習新技術,做過哪些小工具什麼的。
但是有一點,那就是別作假,否則的話很容易被發現的,而且後果一般會很嚴重。
資料結構和演算法
這段時間自己也總結了關於資料結構和演算法相關的一些例子。也看了幾本書,總的來說《劍指Offer》挺好,就我不多的面試經驗來看,大部分面試官都是面試的上面的題,所以有時間的同學可以好好參考參考。
由於本人經驗,技術能力有限,有不恰當,不正確的地方還望批評指正。覺得還可以的也可以給我點個star,(^__^) 嘻嘻……
阿里的那個《技術之瞳》我也看了,裡面內容比較多,但是也比較亂。知識面很廣,但是我感覺深度上還是不太夠。不是很適合我。
其他的類似於Java面試寶典啊這些的,複習的時候認真看一遍,就可以扔一邊了。但是前提是認真看了,因為基礎沒打牢的話,更別提生層建築了。於乎微處見真章。
Java篇
- 集合類的執行緒安全總結:
- 安全的: Vector, Hashtable, concurrentHashMap…
- 不安全的:HashMap, ArrayList, TreeMap, linkedList,HashSet(底層基於HashMap實現)
- 容量相關:
- Vector預設初始容量為10, 自增長量為0。翻倍增長拓展機制。
- ArrayList:預設為10,最大上限為Integer。MAX_SIZE-8;拓展機制:newCapacity = oldCapacity + (oldCapacity >> 1);
- Hashtable:預設大小為11, 裝載因子為0.75
- HashMap: 預設16,裝載因子0.75, 最大上限1<<30
- 集合類的執行緒安全總結:
- Comparator和Comparable的區別
一個類實現了Camparable介面則表明這個類的物件之間是可以相互比較的,這個類物件組成的集合就可以直接使用sort 方法排序。 Comparator可以看成一種演算法的實現,將演算法和資料分離,Comparator也可以在下面兩種環境下使用: Comparable 介面以提供自然排序順序。 對於那些沒有自然順序的類、或者當您想要一個不同於自然順序的順序時,您可以實現 Comparator 介面來定義您自己的排序函式。可以將Comparator傳遞給Collections.sort或Arrays.sort。 Comparator介面 當一個類並未實現Comparable,或者不喜歡預設的Comaparable行為。可以實現Comparator介面 直接實現Comparator的compare介面完成自定義比較類。 例:Arrays.sort(results, new Comparator<RepDataQueryResultVO/>() 陣列排序 RepDataQueryExecutor 例:Collections.sort(lst,new Comparator<TaskPrintSchemeVO/>()
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
Java 的instanceof關鍵字底層實現:
維護了主要超型別(繼承深度)小於7的主陣列, 和次要超型別(判斷的時候需要super鏈遍歷查詢);在位元組碼使用特殊指令對常量池中的相關符號引用進行判斷,來決定true和false。
Java記憶體模型
年輕代,: 伊甸區,兩個存活區(總有一個為空,輪詢轉移)。 (逐級晉升機制)
年老代: 在年輕代中經歷了N次垃圾回收後依然存活的生命期較長的物件。
- 永久代: 存放靜態檔案,如Java類,方法等。持久代對垃圾回收沒有顯著影響。
GC 觸發機制:
新生代GC: 在新物件生成且在伊甸區申請空間失敗的時候會觸發一次對伊甸區的GC,把 存活的物件放置到存活區。通常來說伊甸區的GC會比較頻繁。
Full GC: 對整個堆進行整理,速度慢,次數少。觸發的時機: 年輕代被寫滿, 持久代被寫滿,系統GC被呼叫。
GC 回收標準:
引用計數演算法: 可能導致迴圈引用導致GC效果不好,代替方式有引用標記清理方式
根搜尋演算法: 那些物件可以作為GC Root? 答案是虛擬機器棧中引用的物件,方法區中的類靜態屬性引用的物件 方法區中的常量引用的物件, 本地方法棧中JNI的引用物件
引用狀態:強(被引用著)軟(還有些有那個但不是必須, 二次回收)弱(非必須物件,下次就回收)虛(告知被引用的物件,要被回收啦,作用不大): 程度依次減小,
方法區回收: JVM沒有強調方法區的回收,但是也是非常有用的,對於效率要求較高而言。對於廢棄常量比較好處理 直接判斷有沒有相關的引用即可。對於無效類物件而言有下面幾種方式。該類的例項都被回收;該類的classLoader被回收;該類對應的位元組碼物件Class沒有被任何地方引用,無法在任何地方通過反射來訪問該類的方法。
GC 演算法:
標記清除演算法: 對要進行回收的物件進行標記,在下次GC的時候予以回收。但是碎片化嚴重,對下次的大物件的分配效率不高。
複製演算法: 為了解決效率問題而出現,將記憶體分為可用的兩塊,對於存活的物件
進行復制轉移,碎片化現象減輕。但是代價高啊,可用的只有一半,對於新生代記憶體區採用比較頻繁,
標記整理演算法: 對於老年代物件存活率高,這樣複製演算法不適用,而採用標記整理演算法。將老年代中存活的物件移動到一側,對另外的區域進行GC。
綜上所述,對不同的代區採用不同的GC演算法,會使得GC的效率得到進一步的提升。
- 垃圾收集器: 針對比較常用的HotSpot虛擬機器而言,支援不同型別的垃圾收集器。
- Serial收集器。新生代中採用單執行緒的複製演算法的垃圾收集器。Client端預設
- Parallel收集器。新生代中採用多執行緒的複製演算法的垃圾收集器。Server端預設,高吞吐量。
- Serial Old收集器,採用單執行緒的標記-整理演算法的垃圾收集器,Client端使用。
- Parallel Old收集器, 採用多執行緒的標記-整理演算法的垃圾收集器,Server端使用。
- CMS(Concurrent-Mark-Sweep),以一種獲取最短回收停頓為時間目標的老年代收集器,採用標記-清除演算法。
- G1(Garbage-First),對新生代和老年代不予區分,而是對記憶體堆空間劃分區塊,分配不同的優先順序,使用更有效率的垃圾回收演算法。
- 鎖相關:
- 樂觀鎖機制
- 悲觀鎖: Synchronized就是悲觀鎖的一種,也稱之為獨佔鎖,加了synchronized關鍵字的 程式碼基本上就只能以單執行緒的形式去執行了,它會導致其他需要該資源的執行緒掛起,直到前面的執行緒執行完畢釋放所資源。而另外一種樂觀鎖是一種更高效的機制,它的原理就是每次不加鎖去執行某項操作,如果發生衝突則失敗並重試,直到成功為止,其實本 質上不算鎖,所以很多地方也稱之為自旋。
- ClassLoader相關: 雙親委派模型,以及唯一性的好處。 有哪些類載入器 (Bootstrap ClassLoader[C語言實現,很底層], Ext.., Application)
- 一些原則:
- 小黃鴨測試法
- happen-before原則
- fail-fast原則
- fail-safe原則
- 開閉原則
Java EE知識點儲備
- Spring中 IOC的生命週期:
(<3/>init-method,<1/>intilizingbean介面方法<2/>afterPropertiesSet的先後順序)等。//詳情參考Bean factory implementations should support the standard bean lifecycle interfaces as far as possible. The full set of initialization methods and their standard order is: 1. BeanNameAware's setBeanName 2. BeanClassLoaderAware's setBeanClassLoader 3. BeanFactoryAware's setBeanFactory 4. ResourceLoaderAware's setResourceLoader (only applicable when running in an application context) 5. ApplicationEventPublisherAware's setApplicationEventPublisher (only applicable when running in an application context) 6. MessageSourceAware's setMessageSource (only applicable when running in an application context) 7. ApplicationContextAware's setApplicationContext (only applicable when running in an application context) 8. ServletContextAware's setServletContext (only applicable when running in a web application context) 9. postProcessBeforeInitialization methods of BeanPostProcessors 10. InitializingBean's afterPropertiesSet 11. a custom init-method definition 12. postProcessAfterInitialization methods of BeanPostProcessors On shutdown of a bean factory, the following lifecycle methods apply: 1. DisposableBean's destroy 2. a custom destroy-method definition
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
大致可以這麼來理解:
bean容器建立–通過反射實現bean開始例項化–通過注入資訊設定屬性–可以被呼叫啦–容器被銷燬/bean中設定的destory-method方法被呼叫實現bean的銷燬。
我自己的理解如下:
Strtus: 首先是客戶端發起一個指向servlet容器的請求,被容器上一系列的過濾器獲得主要是ActionContextCleanUp 然後被FilterDispatcher攔截到,經過查詢ActionMapper之後決定呼叫哪個action FilterDispatcher將請求轉發給ActionProxy,ActionMapper內部經過查詢ConfigurationManager找到要呼叫的Action類 ActionProxy代理產生一個ActionInvocation例項,回撥action的execute方法,通過返回的串呼叫相關的jsp頁面 最後反向經過一系列的攔截器,釋放不需要的如ThreadLocal裡面的資料,物件資訊。
SpringMVC: 前端管家DispatcherServlet接收來自客戶端的請求,然後通過handlerMapping查詢到相應的處理器。轉交給handler處理相應的業務邏輯。處理結束後返回一個ModelAndView,返回給客戶端以響應。
Servlet: web伺服器接收到客戶端請求之後,將請求指向一個與url對應的servlet的class,如果已例項化則呼叫init,service,destory。如果未建立,則通過查詢ServletConfig獲取到相關的位元組碼資訊,進行例項化,接著進行上面的操作。
- Hibernate一二級快取,以及lazy-load
- 一級快取: Hibernate內建,預設,切不可解除安裝
- 二級快取你:指SessionFactory的外部快取,可配置可更改,可解除安裝。常用外掛
- EhCache:可作為程序範圍的快取,存放資料的物理介質可以是記憶體或硬碟,對Hibernate的查詢快取提供了支援。 memcache等。
- 惰性載入: 通過延遲載入技術可以避免過多的,過早的載入表裡面的資料,從而降低系統的記憶體開銷。Hibernate中使用代理來實現這一個效果,要想使用在核心配置檔案中對lazy-load屬性設值為true即可。
Spring AOP解決了什麼問題?怎麼實現的?aop與cglib,與asm的關係。
AOP實現了面向切面程式設計。連線點(可以被增強的方法),切入點(被增強的方法),增強(業務中增強的具體邏輯),切面(將增強應用到切入點的過程)
AOP中藉助於動態代理或者cglib實現。動態代理需要介面,cglib是子類增強機制,不能增強final類。
- ASM是一個位元組碼操作框架,直接修改產生位元組碼資料流,效率高,但是人工需要對位元組碼非常的熟悉。
- Spring中的事務傳播屬性:
- REQUESTED: 預設,當前不存在則新增一個事務。
- MANDATORY:沒有事務則失敗
- NEVER: 有事務則失敗
- NOT_SUPPORT: 以非事務的形式執行,如果當前存在事務,則掛起
- SUPPORT: 支援當前事務,如果當前沒有事務,則以非事務形式執行
- NESTED:支援當前事務,新增savepoint,與當前事務同步提交或者回滾,但是內部事務出現異常時,不會影響當前事務的回滾。簡單來說就是內層操作依賴於外層的事務。
- Spring中的BeanFactory和FactoryBean的區別:
- BeanFactory使得管理任何性質的類得以實現,ApplicationContext是BeanFactory的增強。
- FactoryBean提供一個工廠方法,用來得到其他的bean例項。從FactoryBean上得到的bean與普通的bean的配置不同,因為不是由容器產生,所以不需要提供class屬性。如ProxyFactoryBean用於建立代理(根據advisor生成TargetBean的代理,得以實現增強行為)。
計算機網路
HTTP協議, http1.0和http2.0區別:
http2的二進位制壓縮流,完全的多路傳輸。使用報頭壓縮降低了開銷;實現了推送,降低了客戶端多次請求。
報文結構—請求部分: 請求行:請求方法+空格+URL+空格+協議版本+回車+換行符 請求頭: 什麼referer,userAgent啦等等 空行: 回車符+換行符 請求資料: 來自客戶端的請求的資料。
- 報文結構—響應部分: 狀態行:協議版本, 狀態碼啊啥的 訊息報頭:時間, content-type, content-length啥的 響應正文: 正文資料流。
推送模式:
- 長連線: 減少了客戶端輪詢的計算,但是對於伺服器而言有一定壓力,且服務物件會變少。
- 輪詢: 可以很快的監聽到資料變化,但是計算代價較高。
- websocket: 事件佇列模型,解決了上面的問題,伺服器和客戶端都可作為主動方。
但是總的來說有兩大方向: Pull 和 Push; Push對於客戶端而言流量消耗更少;Pull對伺服器端而言壓力稍小。
WebService淺析:
- soap:簡單物件訪問協議,基於xm,可以和諸多應用層協議一起工作,成本高,代價大。
- rest:表屬性狀態轉移,是一個抽象的對於資源訪問的一套設計思路。安全性相比soap較低,但是更流行,成本低。
- WSDL:web service description language.也就是哪個伺服器以什麼方式提供什麼服務的意思,也即服務發現。工作流程: 根據WSDL構造一條soap語句發給伺服器,獲取返回的soap資料並解碼為WSDL,獲取相應服務。
對二者的思考,就是現在的rest也只是soap模式在rest下的借屍還魂,並沒有徹底的改變,而rest缺少一套標準,實現的方式也比較亂,各大廠商也不一致。需要時間的沉澱。
作業系統
- 分頁和分段: 作業系統分頁是為了更好的提高利用率,一個系統頁面大小是一定的,不可改變。而分段則是使用者決定的,來方便使用者
- 程序排程演算法: 短作業優先, 優先順序策略, 輪詢, 分級別的整合法。
資料庫相關
Memcache和Redis:
- IO模型:memcache是多執行緒非阻塞IO,分為主監聽和工作執行緒;redis則是單執行緒事件驅動,效率更高一點。
- 記憶體分配: memcache是記憶體預分配,碎片少,但有空間浪費之嫌; redis是現場分配,碎片化現象存在,但是非臨時資料不會踢到磁碟,仍會留在記憶體,素以更適合儲存而不是cache.
- 資料一致性: memcache採用cas命令可以保證資料一致性;redis使用原子操作保證事務正常執行。
- 儲存方式: memcache使用key-value; redis除此之外還可以儲存list,map等資料結構。
總結: redis的最佳使用方式時全部資料in-memory. redis更多場景是作為memcache的替代品來使用。 當需要除了key-value之外的資料結構支援的時候,redis更適合。 當儲存的資料不鞥唄剔除的時候,使用redis更合適。
資料庫事務以及隔離級別:
四大特性: ACID(原子性[要麼都成功,要麼全失敗], 一致性[事務從一個狀態變成另一個一致性的狀態], 隔離性[一個事務中的行為不會影響到另一個事務], 永續性[改變了資料就不能再撤銷了])。
不考慮事務的時候有可能在讀取資料庫時發生如下問題: 髒讀: 一個事務中讀取了另一個事務中未提交的資料。 不可重複讀: 相同的sql語句,兩次讀取的結果不一致。 幻讀: 一個事務讀取到了另一個事務提交後的結果,或者改變了本次事務的資料的結果。也稱為虛讀。
隔離級別:
- 未提交讀: 最低級別,任何情況都不能保證。
- 提交讀: 可避免髒讀。
- 重複讀: 可避免髒讀,不可重複讀(MySQL預設支援!)
- 序列化: 最強設定。
事務的隔離級別越高,執行的效率就會越低!在JDBC程式碼中可以對connection物件設定相應的隔離級別。
資料庫資料結構:
- mysql儲存引擎中索引的實現機制;使用B-Tree優勢在於出度大,磁碟預讀效果好,與之相比,二叉樹,紅黑樹則不好。理論上來講,出度越大,索引的效率越高。儘量採用自增欄位作為索引,因為按頁儲存的時候不需要移動資料塊,而不重複的欄位則類似於隨機方式,需要移動資料塊,效率會差點。這就是因為innodb的聚集特性(資料在磁碟上的儲存順序和索引順序一致)決定的。
2.資料庫事務的幾種粒度;表鎖(不會產生死鎖,但是併發度低), 頁鎖(有可能產生死鎖,但是用的不多), 行鎖(併發度高,但是有可能產生死鎖)。
- 3.行鎖,表鎖;樂觀鎖,悲觀鎖 悲觀鎖:在讀取資料時鎖住那幾行,其他對這幾行的更新需要等到悲觀鎖結束時才能繼續 樂觀鎖:讀取資料時不鎖,更新時檢查是否資料已經被更新過,如果是則取消當前更新 一般在悲觀鎖的等待時間過長而不能接受時我們才會選擇樂觀鎖
- Mysql是怎麼實現repeable read的,(next-key)?
- innode的鎖,死鎖和 索引相關的東西。
- 隔離級別: 未提交讀,提交讀, 重複讀,序列化(一次只有一個人可以操作)
- innodb預設採用行鎖,對資料採用repeatable read,也就是事務開始後讀取到的結果會一致,這和oracle的committed read(只能讀取提交的事務資料,有可能產生兩次結果不一致的問題)不同。
- 行鎖併發度高,不易產生死鎖;表級鎖併發度低,不會產生死鎖。
- 鎖本身又分為讀鎖和寫鎖; 按照共享與否大致分為共享鎖和排它鎖等四個。
- mysql死鎖: 行級鎖並不是直接鎖行記錄,而是鎖索引(主鍵索引和非主鍵索引)。
- 一條sql語句如操作了主鍵索引,則會鎖住此主鍵索引;操作了非主鍵索引,則先鎖住非主鍵索引,再鎖住主鍵索引。
- 在update,delete操作時,mysql還會鎖住where下相鄰的記錄,實現next-key locking. 可以很好的解決“幻讀”問題。
- SQL 優化入門
- 使用內部函式; 避免select*; 使用表的別名,提高效率和準確度; 用[not]exist 代替[not]in; 使用索引;
- 分表,分庫,精簡表結構,欄位結構;等等。
XML
DTD(Document Type Define,文件定義型別), schema( XSD, XML Schema Document)之間的區別和聯絡
- DTD:採用非XML語法規範,拓展性差。命名衝突不易解決。
- schema: 採用XML語法規範
常識性知識
- 查詢Linux中佔用磁碟最大的檔案:
du path -type f -size +NumberG | sort -n -r | head -n 10
找出給定目錄下以G為單位的最大的10個檔案,並排序輸出。
全域性唯一ID問題:
時間戳,加去中心化,加邏輯分片,機器號等
- 什麼是布隆過濾器,其實現原理是? False positive指的是?
- 布隆過濾器就是使用一個很大的陣列,根據K個雜湊函式得到K個位置,在陣列中將這K個位置對應的值設定為1;
- 查詢的時候,仍舊採用這K個雜湊函式對查詢串進行雜湊運算,判斷對應的K歌位置是否為1;有可能因為其他的串的
- 插入導致這K個位置全部為1,導致誤判現象的產生,不過這種情況發生的可能性很小,畢竟要與K個雜湊位置都一致。
- RPC的負載均衡、服務發現怎麼做的
- 單點LB: 容易出現單點失效問題,且需要配合DNS服務,效能開銷略大
- LB整合到客戶端: 對於開發成本較大,平臺限制。但是對於服務發現和健康檢查而言,伺服器端壓力減小。
- LB作為主機單程序,相當於將LB程序和服務程序隔離開,一個主機掛了隻影響單個主機服務,但是配置較為麻煩,環節多,出錯除錯較為困難。
Linux使用及問題排查:
- grep,awk,sed; 是否自己寫過shell指令碼;
常見的cpu load過高,us過高,一般是什麼問題。引申出是否用過top,jstat,jstack等。
可以先ps -aux (或者top, htop)找到佔比高的程序號,然後使用ps -Lp 122427 cu找到對應的java程序的每個執行緒的CPU使用率,追蹤執行緒內部執行的狀況。 常見的記憶體問題一般有哪些。 引申出是否用過free,top, jmap等。
總結
林林總總的一萬多字了,但是這還遠遠不能覆蓋全部。而且距離一個合格的Java程式設計師僅僅知道這些還遠遠不夠,我們能做的就是儘可能的讓自己接近那個標準吧。
上面這些連結也好,總結也好,大家還是需要有自己的理解。
“盡信書,則不如無書!”,其實也是這麼個道理,帶著思考來閱讀,效率,效果都可能會更好。
最後,希望大家都能找到自己心儀的offer。