2019螞蟻金服Java必問面試題(一面)

一面
1、自我介紹、自己做的項目和技術領域

2、項目中的監控:那個監控指標常見的有哪些?

答:CPU、內存、IO 等等。建議下載個nmon工具,裏面有各個指標。

數據庫:Mysql(緩存命中、索引、單條SQL性能、數據庫線程數、數據池連接數)中間件:1.消息2、負載均衡3、緩存(包括線程數、連接數、日誌)。

網絡: 吞吐量、吞吐率

應用: jvm內存、日誌、Full GC頻率

3、註冊中心你瞭解了哪些?

答:Consul 、Eureka、ZooKeeper

4、項目用 Spring 比較多,有沒有了解 Spring 的原理?AOP 和 IOC 的原理

答:

(1). IoC(Inversion of Control)是指容器控制程序對象之間的關係,而不是傳統實現中,由程序代碼直接操控。控制權由應用代碼中轉到了外部容器,控制權的轉移是所謂反轉。 對於Spring而言,就是由Spring來控制對象的生命週期和對象之間的關係;IoC還有另外一個名字——“依賴注入(Dependency Injection)”。從名字上理解,所謂依賴注入,即組件之間的依賴關係由容器在運行期決定,即由容器動態地將某種依賴關係注入到組件之中。

(2). 在Spring的工作方式中,所有的類都會在spring容器中登記,告訴spring這是個什麼東西,你需要什麼東西,然後spring會在系統運行到適當的時候,把你要的東西主動給你,同時也把你交給其他需要你的東西。所有的類的創建、銷燬都由 spring來控制,也就是說控制對象生存週期的不再是引用它的對象,而是spring。對於某個具體的對象而言,以前是它控制其他對象,現在是所有對象都被spring控制,所以這叫控制反轉。

(3). 在系統運行中,動態的向某個對象提供它所需要的其他對象。

(4). 依賴注入的思想是通過反射機制實現的,在實例化一個類時,它通過反射調用類中set方法將事先保存在HashMap中的類屬性注入到類中。 總而言之,在傳統的對象創建方式中,通常由調用者來創建被調用者的實例,而在Spring中創建被調用者的工作由Spring來完成,然後注入調用者,即所謂的依賴注入or控制反轉。 注入方式有兩種:依賴注入和設置注入; IoC的優點:降低了組件之間的耦合,降低了業務對象之間替換的複雜性,使之能夠靈活的管理對象。

5、AOP(Aspect Oriented Programming)

(1). AOP面向方面編程基於IoC,是對OOP的有益補充;

(2). AOP利用一種稱爲“橫切”的技術,剖解開封裝的對象內部,並將那些影響了 多個類的公共行爲封裝到一個可重用模塊,並將其名爲“Aspect”,即方面。所謂“方面”,簡單地說,就是將那些與業務無關,卻爲業務模塊所共同調用的 邏輯或責任封裝起來,比如日誌記錄,便於減少系統的重複代碼,降低模塊間的耦合度,並有利於未來的可操作性和可維護性。

(3). AOP代表的是一個橫向的關 系,將“對象”比作一個空心的圓柱體,其中封裝的是對象的屬性和行爲;則面向方面編程的方法,就是將這個圓柱體以切面形式剖開,選擇性的提供業務邏輯。而 剖開的切面,也就是所謂的“方面”了。然後它又以巧奪天工的妙手將這些剖開的切面復原,不留痕跡,但完成了效果。

(4). 實現AOP的技術,主要分爲兩大類:一是採用動態代理技術,利用截取消息的方式,對該消息進行裝飾,以取代原有對象行爲的執行;二是採用靜態織入的方式,引入特定的語法創建“方面”,從而使得編譯器可以在編譯期間織入有關“方面”的代碼。

(5). Spring實現AOP:JDK動態代理和CGLIB代理 JDK動態代理:其代理對象必須是某個接口的實現,它是通過在運行期間創建一個接口的實現類來完成對目標對象的代理;其核心的兩個類是InvocationHandler和Proxy。 CGLIB代理:實現原理類似於JDK動態代理,只是它在運行期間生成的代理對象是針對目標類擴展的子類。CGLIB是高效的代碼生成包,底層是依靠ASM(開源的java字節碼編輯類庫)操作字節碼實現的,性能比JDK強;需要引入包asm.jar和cglib.jar。 使用AspectJ注入式切面和@AspectJ註解驅動的切面實際上底層也是通過動態代理實現的。

6、Spring Boot除了自動配置,相比傳統的 Spring 有什麼其他的區別?

爲Spring 生態系統的開發提供一種更簡潔的方式,提供了很多非功能性特性,例如:嵌入式 Server,Security,統計,健康檢查,外部配置等等,主要體現在以下幾點:

(1).Spring Boot可以建立獨立的Spring應用程序;

(2).內嵌瞭如Tomcat,Jetty和Undertow這樣的容器,也就是說可以直接跑起來,用不着再做部署工作了;

(3).無需再像Spring那樣搞一堆繁瑣的xml文件的配置;

(4).可以自動配置Spring。SpringBoot將原有的XML配置改爲Java配置,將bean注入改爲使用註解注入的方式(@Autowire),並將多個xml、properties配置濃縮在一個appliaction.yml配置文件中。

(5).提供了一些現有的功能,如量度工具,表單數據驗證以及一些外部配置這樣的一些第三方功能;

(6).整合常用依賴(開發庫,例如spring-webmvc、jackson-json、validation-api和tomcat等),提供的POM可以簡化Maven的配置。當我們引入核心依賴時,SpringBoot會自引入其他依賴。

7、Spring Cloud 有了解多少?

Spring Cloud是一系列框架的有序集合。它利用Spring Boot的開發便利性巧妙地簡化了分佈式系統基礎設施的開發,如服務發現註冊、配置中心、消息總線、負載均衡、斷路器、數據監控等,都可以用Spring Boot的開發風格做到一鍵啓動和部署。Spring Cloud並沒有重複製造輪子,它只是將目前各家公司開發的比較成熟、經得起實際考驗的服務框架組合起來,通過Spring Boot風格進行再封裝屏蔽掉了複雜的配置和實現原理,最終給開發者留出了一套簡單易懂、易部署和易維護的分佈式系統開發工具包。

8、Spring Bean 的生命週期

一個Bean從創建到銷燬,如果是用BeanFactory來生成,管理Bean的話

Spring上下文中的Bean也類似,如下

(1)實例化一個Bean--也就是我們常說的new;

(2)按照Spring上下文對實例化的Bean進行配置--也就是IOC注入;

(3)如果這個Bean已經實現了BeanNameAware接口,會調用它實現的setBeanName(String)方法,此處傳遞的就是Spring配置文件中Bean的id值

(4)如果這個Bean已經實現了BeanFactoryAware接口,會調用它實現的setBeanFactory(setBeanFactory(BeanFactory)傳遞的是Spring工廠自身(可以用這個方式來獲取其它Bean,只需在Spring配置文件中配置一個普通的Bean就可以);

(5)如果這個Bean已經實現了ApplicationContextAware接口,會調用setApplicationContext(ApplicationContext)方法,傳入Spring上下文(同樣這個方式也可以實現步驟4的內容,但比4更好,因爲ApplicationContext是BeanFactory的子接口,有更多的實現方法);

(6)如果這個Bean關聯了BeanPostProcessor接口,將會調用postProcessBeforeInitialization(Object obj, String s)方法,BeanPostProcessor經常被用作是Bean內容的更改,並且由於這個是在Bean初始化結束時調用那個的方法,也可以被應用於內存或緩存技術;

(7)如果Bean在Spring配置文件中配置了init-method屬性會自動調用其配置的初始化方法。

(8)如果這個Bean關聯了BeanPostProcessor接口,將會調用postProcessAfterInitialization(Object obj, String s)方法、;

注:以上工作完成以後就可以應用這個Bean了,那這個Bean是一個Singleton的,所以一般情況下我們調用同一個id的Bean會是在內容地址相同的實例,當然在Spring配置文件中也可以配置非Singleton,這裏我們不做贅述。

9、HashMap 和 hashTable 區別?

區別:Hashtable是線程安全的,效率比較低

Hashtable既不支持Null key也不支持Null value。Hashtable的put()方法的註釋中有說明

Hashtable默認的初始大小爲11,之後每次擴充,容量變爲原來的2n+1。

HashMap默認的初始化大小爲16。之後每次擴充,容量變爲原來的2倍

Hashtable在計算元素的位置時需要進行一次除法運算,而除法運算是比較耗時的

HashMap爲了提高計算效率,將哈希表的大小固定爲了2的冪,這樣在取模預算時,不需要做除法,只需要做位運算。位運算比除法的效率要高很多。

HashMap是繼承自AbstractMap類,而HashTable是繼承自Dictionary類。不過它們都實現了同時實現了map、Cloneable(可複製)、Serializable(可序列化)這三個接口

10、Object 的 hashcode 方法重寫了,equals 方法要不要改?

不需要,Ojbect類中有兩個方法equals、hashCode,這兩個方法都是用來比較兩個對象是否相等的,如果兩個對象相等(equal),那麼必須擁有相同 的哈希碼(hash code)

即使兩個對象有相同的哈希值(hash code),他們不一定相等

重寫equals()方法就必須重寫hashCode(),但重寫hashcode方法不一定要重寫equals方法

11、Hashmap 線程不安全的出現場景

用ConcurrentHashMap 線程安全

多線程處理時hashmap線程不安全

首先hashmap裏這個size沒有用volatile關鍵字修飾,代表這不是一個內存可見的變量,線程操作數據的時候一般是從主存拷貝一個變量副本進行操作,操作完成過後在把size的值寫回到主存size的

線程不安全問題應該屬於併發問題之一的,屬於相對高級的問題了。這個時候的問題已經不僅僅侷限於代碼層面了,很多時候需要結合JVM一起分析了

12、JDK 中有哪幾個線程池?

順帶把線程池講了個遍

JUC提供了調度器對象Executors來創建線程池,可創建的線程池有四種

(1)newFixedThreadPool創建一個指定工作線程數量的線程池。每當提交一個任務就創建一個工作線程,如果工作線程數量達到線程池初始的最大數,則將提交的任務存入到池隊列中。

(2)newCachedThreadPool創建一個可緩存的線程池。這種類型的線程池特點是:

1).工作線程的創建數量幾乎沒有限制(其實也有限制的,數目爲Interger. MAX_VALUE), 這樣可靈活的往線程池中添加線程。

2).如果長時間沒有往線程池中提交任務,即如果工作線程空閒了指定的時間(默認爲1分鐘),則該工作線程將自動終止。終止後,如果你又提交了新的任務,則線程池重新創建一個工作線程。

(3)newSingleThreadExecutor創建一個單線程化的Executor,即只創建唯一的工作者線程來執行任務,如果這個線程異常結束,會有另一個取代它,保證順序執行(我覺得這點是它的特色)。單工作線程最大的特點是可保證順序地執行各個任務,並且在任意給定的時間不會有多個線程是活動的 。

(4)newScheduleThreadPool創建一個定長的線程池,而且支持定時的以及週期性的任務執行,類似於Timer。(這種線程池原理暫還沒完全瞭解透徹)

13、查看 SQL 是不是使用了索引?(有什麼工具)

在select語句前加上EXPLAIN即可

14、TCP 和 UDP 的區別?TCP 數據傳輸過程中怎麼做到可靠的?

UDP(User Data Protocol,用戶數據報協議)是與TCP相對應的協議。它是屬於TCP/IP協議族中的一種

(1)爲了保證數據包的可靠傳遞,發送方必須把已發送的數據包保留在緩衝區;

(2)併爲每個已發送的數據包啓動一個超時定時器;

(3)如在定時器超時之前收到了對方發來的應答信息(可能是對本包的應答,也可以是對本包後續包的應答),則釋放該數據包占用的緩衝區;

(4)否則,重傳該數據包,直到收到應答或重傳次數超過規定的最大次數爲止。

(5)接收方收到數據包後,先進行CRC校驗,如果正確則把數據交給上層協議,然後給發送方發送一個累計應答包,表明該數據已收到,如果接收方正好也有數據要發給發送方,應答包也可方在數據包中捎帶過去。

15、說下你知道的排序算法吧

常見的內部排序算法有:插入排序、希爾排序、選擇排序、冒泡排序、歸併排序、快速排序、堆排序、基數排序等

16、查找一個數組的中位數?

通過二分查找法來找中位數

基本思想是:假設ar1[i]是合併後的中位數,那麼ar1[i]大於ar1[]中前i-1個數,且大於ar2[]中前j=n-i-1個數。通過ar1[i]和ar2[j]、ar2[j+1]兩個數的比較,在ar1[i]的左邊或者ar1[i]右邊繼續進行二分查找。對於兩個數組 ar1[] 和ar2[], 先在 ar1[] 中做二分查找。如果在ar1[]中沒找到中位數, 繼續在ar2[]中查找。

算法流程:

1) 得到數組ar1[]最中間的數,假設下標爲i.

2) 計算對應在數組ar2[]的下標j,j = n-i-1

3) 如果 ar1[i] >= ar2[j] and ar1[i] <= ar2[j+1],那麼 ar1[i] 和 ar2[j] 就是兩個中間元素,返回ar2[j] 和 ar1[i] 的平均值

4) 如果 ar1[i] 大於 ar2[j] 和 ar2[j+1] 那麼在ar1[i]的左部分做二分查找(i.e., arr[left ... i-1])

5) 如果 ar1[i] 小於 ar2[j] 和 ar2[j+1] 那麼在ar1[i]的右部分做二分查找(i.e., arr[i+1....right])

6) 如果到達數組ar1[]的邊界(left or right),則在數組ar2[]中做二分查找

時間複雜度:O(logn)。

螞蟻完整面試題(一面、二面)、學習視頻、大廠面試題、java核心資料整理:https://shimo.im/docs/TC9Jq63Tp6HvTXdg/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章