兩周的時間,面試了杭州將近20多家軟件公司,有時下熱門的互聯網行業,也有傳統行業。涉及的行業眾多,社交直播平台的、安防監控的、消費信貸的、大數據風控、互聯網醫療、電商的等等。這里寫一下自己面試過程中的遇到的面試題,借以反思一下自己面試的不足。
1.Spring框架的IOC和AOP原理;
IOC:在傳統的程序實現里,由代碼來控制組件之間的關系,使用new關鍵字來實現兩個組件之間的結合,這樣會帶來對象之間的耦合,像齒輪轉動一樣,有了IOC,它將實現組件關系從內部像外部轉移,由容器在運行期間將依賴關系注入到組件中。根據類名動態的生成對象,這種編程方式可以在對象生成的時候才決定到底是哪一種對象。
AOP:通過在代理對象中包裹切面,運行期間將切面織入到容器管理的bean中,代理類封裝了目標類,並攔截被通知方法的調用,再將調用轉發給真正的目標bean。當攔截到方法調用,在調用目標bean之前代理會執行切面邏輯。AOP提供了兩種方式來生成代理對象:JDKProxy和Cglib,具體使用哪種方式由AopProxyFactory根據AdvisedSupport對象的配置來決定。默認策略是如果目標類是接口就使用JDK動態代理請求,否則使用Cglib來代理。
2.類加載機制
Class文件由類裝載器裝載后,在jvm中將形成一份描述class結構元信息對象,通過該對象可以獲知class的結構信息,如構造函數、屬性和方法。
雙親委派模型:
如果一個類加載器接收到類加載請求,它首先把這個請求委托給父類加載器去完成,因此,所有加載請求都應該傳送到頂層啟動類加載器中,只有父加載器反饋自己無法完成這個加載請求,子加載器才會嘗試自己去加載。
裝載:
- 通過一個類的全限定名獲取此類的二進制字節流;
- 將這個字節流所代表的靜態存儲結構轉化為方法區運行時的數據結構;
- 在java堆中生成一個代表這個類的java.lang.Class作為方法區這些數據的入口;
驗證:
- 文件格式驗證:保證輸入的字節流能正確解析並存儲於方法區內;
- 元數據驗證:對類中的各個數據類型進行校驗分析;
- 對方法體驗證,保證被校驗的類的方法在運行中不會做出危害虛擬機安全的行為;
- 符號引用驗證:對常量池中的各種符號引用進行匹配校驗;
准備:
正式為類變量分配內存,並設置變量初始值,內存都將在方法區進行分配;
解析:
虛擬機將常量池中的符號引用替換為直接引用的過程
3.分布式事務
基於XA協議的兩階段提交和消息+最終一致性
4.常用設計模式
單例、工廠、適配器、責任鏈、門面、裝飾、策略、觀察者等 說出幾個,並知道實現方法和應用場景。
5.sql調優
- 盡量避免使用查詢模糊匹配,會導致索引失效。like'%param%'
- 避免對索引字段進行計算操作,在索引字段上使用not/<>/!=等,避免在索引字段上出現isNull/isNotNull,以及不要在索引上使用函數或空值;
- 嵌套子查詢可以考慮使用臨時表
- union all能解決的場景不要使用union
- 避免在where語句中出現in/not in/having
- 不要以字符格式聲明數字
- select 語句要標識要查詢的字段,不要總是select *!!
6.分庫分表策略
- 中間變量=user_id%(分庫數量*每個分表數量)
- 庫=取整(中間變量/每個庫表數量)
- 表=中間變量%每個庫表數量
7.@Resource和@Autowired區別
同:都是做bean注入使用
異:@AutoWired默認按照類型byType裝配對象,依賴對象必須存在,如果允許null值,可以設置required屬性為false。@Resource默認按照byName注入,由j2ee提供;
8.java7新特性、java8新特性
9.servlet生命周期
初始化階段調用init方法
響應客戶請求調用service方法
終止階段調用destory方法
10.頁面加載慢的原因
減少請求數、減少資源大小、找最快的服務器三方面去優化。
優化圖片資源的格式和大小;
開啟網絡壓縮;
使用瀏覽器緩存;
減少重定向,每一次重定向都會導致瀏覽器重新加載請求,延長加載時間;
使用cdn緩存靜態資源
減少dns解析次數
壓縮js和css去掉空格等
11.set底層實現
利用map的key不能重復
12.jvm分代垃圾回收
Eden區用來創建新對象,滿觸發一次young GC,將還被使用的對象復制到from區,Eden區再次用完再次用完,再觸發一次young GC,將eden和from區的還在被使用的對象復制到to區,下一次young GC則是將Eden區和to區還被使用的對象復制到from區,超過閾值對象還沒有被釋放,復制到old generation。old用完觸發full GC。合理設置young generation和old generation避免產生full gc.
13.負載均衡算法
輪詢、加權輪詢、隨機、最少連接、源地址散列。
14.高可用架構設計
主要手段:數據和服務的冗余備份和失效轉移
15.高可用服務
分級管理,核心應用與服務優先使用更好的硬件
超時設置,一旦超時,通信框架拋出異常,應用可選擇重試和請求轉移
異步調用,消費者在消息隊列取
服務降級,拒絕服務和關閉服務,保證核心應用和功能能正常運行
冪等性設計,保證服務調用多次和一次結果相同;
16.反射機制
17.分布式緩存的一致性hash(網易)
18.https原理(網易)
19.樂觀鎖和悲觀鎖(網易)
20.數據庫隔離級別
21.spring事務傳播屬性
22.301與302區別(網易)
301永久轉移 302暫時轉移
23.get與post區別
24.表建索引規則
避免對大數據類型建立索引
經常使用group by和order by的建立索引
用於連接的列建立索引
對那些頻繁出現在where子句中的建立索引
確定表是大量查詢還是增刪改
25.跨域有幾種方式(網易)
26.HashMap與ConcurrentHashMap
27.分布式鎖如何實現?
28.kafka技術優點,以及是怎么實現的?
29.Tcp/IP協議的三次握手與四次揮手
30.線程間如何通信?(網易)
同步(synchronized)比如線程A和線程B都持有一個object,線程B需要等到A執行后才能運行。A與B就實現了通信,本質上是共享內存通信,多個線程需要訪問同一個共享變量,誰拿了鎖就可以先執行
wait/notify機制,A調用wait進入阻塞,條件滿足時,B調用notify喚醒A
管道通信就是使用PipedInputStream和PipedOutputStream進行通信
31.spring如何處理循環依賴?
構造器循環依賴:
<bean id="A" class="com.donsun.student.StudentA">
2 <constructor-arg index="0" ref="B"></constructor-arg>
3 </bean>
4 <bean id="B" class="com.donsun.student.StudentB">
5 <constructor-arg index="0" ref="C"></constructor-arg>
6 </bean>
7 <bean id="C" class="com.donsun.student.StudentC">
8 <constructor-arg index="0" ref="A"></constructor-arg>
9 </bean>
Spring容器會將每一個正在創建的Bean 標識符放在一個“當前創建Bean池”中,Bean標識符在創建過程中將一直保在這個池中,因此如果在創建Bean過程中發現自己已經在“當前創建Bean池”里時將拋出BeanCurrentlyInCreationException異常表示循環依賴;而對於創建完畢的Bean將從“當前創建Bean池”中清除掉。
setter循環依賴(單例):
<!--scope="singleton"(默認就是單例方式) -->
2 <bean id="A" class="com.donsun.student.StudentA" scope="singleton">
3 <property name="studentB" ref="B"></property>
4 </bean>
5 <bean id="B" class="com.donsun.student.StudentB" scope="singleton">
6 <property name="studentC" ref="C"></property>
7 </bean>
8 <bean id="C" class="com.donsun.student.StudentC" scope="singleton">
9 <property name="studentA" ref="A"></property>
10 </bean>
這種情況下,Spring先實例化Bean對象 ,此時Spring會將這個實例化結束的對象放到一個Map中,並且Spring提供了獲取這個未設置屬性的實例化對象引用的方法。當Spring實例化了StudentA、StudentB、StudentC后,緊接着會去設置對象的屬性,此時StudentA依賴StudentB,就會去Map中取出存在里面的單例StudentB對象,以此類推,不會出來循環的問題;
下面是Spring源碼中的實現方法,。以下的源碼在Spring的Bean包中的DefaultSingletonBeanRegistry.Java類中
1 /** Cache of singleton objects: bean name --> bean instance(緩存單例實例化對象的Map集合) */
2 private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(64);
3
4 /** Cache of singleton factories: bean name --> ObjectFactory(單例的工廠Bean緩存集合) */
5 private final Map<String, ObjectFactory> singletonFactories = new HashMap<String, ObjectFactory>(16);
6
7 /** Cache of early singleton objects: bean name --> bean instance(早期的單身對象緩存集合) */
8 private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);
9
10 /** Set of registered singletons, containing the bean names in registration order(單例的實例化對象名稱集合) */
11 private final Set<String> registeredSingletons = new LinkedHashSet<String>(64);
12 /**
13 * 添加單例實例
14 * 解決循環引用的問題
15 * Add the given singleton factory for building the specified singleton
16 * if necessary.
17 * <p>To be called for eager registration of singletons, e.g. to be able to
18 * resolve circular references.
19 * @param beanName the name of the bean
20 * @param singletonFactory the factory for the singleton object
21 */
22 protected void addSingletonFactory(String beanName, ObjectFactory singletonFactory) {
23 Assert.notNull(singletonFactory, "Singleton factory must not be null");
24 synchronized (this.singletonObjects) {
25 if (!this.singletonObjects.containsKey(beanName)) {
26 this.singletonFactories.put(beanName, singletonFactory);
27 this.earlySingletonObjects.remove(beanName);
28 this.registeredSingletons.add(beanName);
29 }
30 }
31 }
setter循環依賴(prototype):
2 <bean id="A" class="com.donsun.student.StudentA" scope="prototype">
3 <property name="studentB" ref="B"></property>
4 </bean>
5 <bean id="B" class="com.donsun.student.StudentB" scope="prototype">
6 <property name="studentC" ref="C"></property>
7 </bean>
8 <bean id="C" class="com.donsun.student.StudentC" scope="prototype">
9 <property name="studentA" ref="A"></property>
10 </bean>
因為“prototype”作用域的Bean,Spring容器不進行緩存,因此無法提前暴露一個創建中的Bean。拋出BeanCurrentlyInCreationException
32.try{}catch(){}finally{}return各種變化返回值
1、不管有沒有出現異常,finally塊中代碼都會執行;
2、當try和catch中有return時,finally仍然會執行;
3、finally是在return后面的表達式運算后執行的(此時並沒有返回運算后的值,而是先把要返回的值保存起來,不管finally中的代碼怎么樣,返回的值都不會改變,仍然是之前保存的值),所以函數返回值是在finally執行前確定的;
4、finally中最好不要包含return,否則程序會提前退出,返回值不是try或catch中保存的返回值。
33.redis回收策略
34.集合迭代效率對比
35.ArrayList與LinkedList區別
36.jvm內存模型
37.java序列化算法
38.紅黑樹
39.synchronized用到的場景
40.線程池配置關鍵參數
41.平時用過哪些框架,看過哪些源碼以及實現原理
42.畫出你做過項目的架構圖
43.廣度優先遍歷與深度優先遍歷
44.你覺得你最擅長什么?
45.項目怎么改為分布式?
46.HashMap中有個對象transient Entry[] table,為什么要加上關鍵字transient呢?
1.看一下HashMap.get()/put()知道, 讀寫Map是根據Object.hashcode()來確定從哪個bucket讀/寫. 而Object.hashcode()是native方法, 不同的JVM里可能是不一樣的,如果你使用默認的序列化,那么反序列化后,元素的位置和之前的是保持一致的,可是由於 hashCode 的值不一樣了,那么定位函數 indexOf()返回的元素下標就會不同,這樣不是我們所想要的結果.
2.transient 是表明該數據不參與序列化。因為 HashMap 中的存儲數據的數組數據成員中,數組還有很多的空間沒有被使用,沒有被使用到的空間被序列化沒有意義。所以需要手動使用 writeObject() 方法,只序列化實際存儲元素的數組。
47.分布式鎖使用場景(網易)
48.dubbo版本號作用(網易)
當一個接口實現,出現不兼容升級時,可以用版本號過渡,版本號不同的服務相互間
不引用。
在低壓力時間段,先升級一半提供者為新版本
再將所有消費者升級為新版本
然后將剩下的一半提供者升級為新版本
49.秒殺系統設計(網易)
50.內部類與嵌套類區別
51.算法:遞歸實現回文(網易)
52.算法:程序實現字符串有哪些英文字母空格數字,不能用ascii碼來判斷
53.zookeeper分布式鎖節點與其他節點區別(網易)
PERSISTENT_SEQUENTIAL 順序自動編號持久化節點,這種節點會根據當前已存在的節點數自動加
1
54.項目中遇到的問題以及如何解決的?
55.springMvc完整工作流程,哪些關鍵的類
56.spring用到的設計模式舉例
57.死鎖條件
教訓:
1.按照STAR法則制作簡歷;
2.不同的公司崗位需求肯定不同,簡歷要有針對性,不要只准備一份簡歷;
3.要按照崗位需求,在項目中突出與之匹配的技能,先過了篩選這關;
4.要准備好才投簡歷,不然自己心儀的公司讓你去面試,結果你沒怎么准備,被刷了,那么機會可能就沒有了!
5.項目里列出的技術,不能停留於表面的認識,至少你自己心里能過的去,不然你的簡歷在面試官那里不是羊入虎口嗎~!
6.互聯網公司比較關注分布式、中間件、並發編程、鎖之類的,建議多了解下java並發包以及市面流行的中間件;