2017年阿里內推一面面經(不斷更新)

HuangQinJian發表於2017-03-20

在3月1號投完簡歷,做好測評以後,我是一直等啊等,始終期待著一面的到來。

好不容易在3月8號這天中午12點10左右接到了來自阿里的面試電話。

剛開始,我是一臉的懵逼啊,面試官問我:“你是不是面過了???”我是一臉黑臉問號.jpg。Excuse me?在我一番解釋後,終於進入了正題。


首先還是自我介紹。然後下面是問題清單:

1、平時在專案中主要負責哪塊技術啊?(我回答資料庫方面的程式碼)好,那麼請問,你所知道的資料庫方面所需要注意的地方有什麼?怎麼優化資料庫?

引申出來以後,他又我問了我關於left join與right join的區別,(我回答了出來),然後,他又問我那inner join呢?(我當時是忘記了,一臉懵逼啊,絕望放棄回答)?用很多join好嗎,有什麼 缺點?(效率降低)

這裡寫圖片描述
這裡寫圖片描述

  • 關於索引:

    • 應該建索引的欄位:
      1.經常作為查詢條件的欄位
      2.外來鍵
      3.經常需要排序的欄位
      4.分組排序的欄位

    • 應該少建或者不建索引的欄位有:
      1.表記錄太少
      2.經常需要插入,刪除,修改的表,
      3.表中資料重複且分佈平均的欄位


2、HTTP的特點,TCP/UDP特點以及區別?

1.支援客戶/伺服器模式。

2.簡單快速:客戶向伺服器請求服務時,只需傳送請求方法和路徑。請求方法常用的有GET、HEAD、POST。每種方法規定了客戶與伺服器聯絡的型別不同。由於HTTP協議簡單,使得HTTP伺服器的程式規模小,因而通訊速度很快。

3.靈活:HTTP允許傳輸任意型別的資料物件。正在傳輸的型別由Content-Type加以標記。

4.無連線:無連線的含義是限制每次連線只處理一個請求。伺服器處理完客戶的請求,並收到客戶的應答後,即斷開連線。採用這種方式可以節省傳輸時間。

5.無狀態:HTTP協議是無狀態協議。無狀態是指協議對於事務處理沒有記憶能力。缺少狀態意味著如果後續處理需要前面的資訊,則它必須重傳,這樣可能導致每次連線傳送的資料量增大。另一方面,在伺服器不需要先前資訊時它的應答就較快。


3、HashMap、HashTable、ConCurrentHasgMap的區別以及實現原理?
ConCurrentHasgMap呼叫get()方法的時候有鎖嗎?

對於put和remove操作,是使用鎖同步來進行的,不過是用的ReentrantLock而不是synchronized,效能上要更高一些。它們的實現前文都已經提到過,就沒什麼可分析的了。

友情連結:ConCurrentHasgMap原始碼分析

我們還需要知道一點,ConcurrentHashMap的迭代器不是Fast-Fail的方式,所以在迭代的過程中別其他執行緒新增/刪除了元素,不會丟擲異常,也不能體現出元素的改動。但也沒有關係,因為每個entry的成員除了value都是final修飾的,暴漏出去也不會對其他元素造成影響。

  • 為什麼hashmap擴容是是擴大成原來的2倍,而不是3倍?

友情連結:深入理解HashMap(及hash函式的真正巧妙之處)


4、怎麼實現併發程式設計?請詳細描述?

鎖機制(Lock)、CAS無鎖演算法、Synchronized區別


5、類載入機制(如果自己寫幾個Jar包,應該放哪裡?)


6、String、StringBuffer、StringBuilder的區別?

如果StringBuilder後增加一個字串常量,並且這時候是多執行緒執行,那這時候StringBuilder是執行緒安全的嗎?

字串常量就是不能改變該物件,而後者是可是改變的字串物件,他不像String一樣,需要每次建立,後兩者是在原有的字串物件進行操作的。


7、JDK7、8的區別?

在JMM方面的區別:

永久代
在JDK8之前的HotSpot實現中,類的後設資料如方法資料、方法資訊(位元組碼,棧和變數大小)、執行時常量池、已確定的符號引用和虛方法表等被儲存在永久代中,32位預設永久代的大小為64M,64位預設為85M,可以通過引數-XX:MaxPermSize進行設定,一旦類的後設資料超過了永久代大小,就會丟擲OOM異常。

虛擬機器團隊在JDK8的HotSpot中,把永久代從Java堆中移除了,並把類的後設資料直接儲存在本地記憶體區域(堆外記憶體),稱之為元空間。

這樣做有什麼好處?
有經驗的同學會發現,對永久代的調優過程非常困難,永久代的大小很難確定,其中涉及到太多因素,如類的總數、常量池大小和方法數量等,而且永久代的資料可能會隨著每一次Full GC而發生移動。

而在JDK8中,類的後設資料儲存在本地記憶體中,元空間的最大可分配空間就是系統可用記憶體空間,可以避免永久代的記憶體溢位問題,不過需要監控記憶體的消耗情況,一旦發生記憶體洩漏,會佔用大量的本地記憶體。

ps:JDK7之前的HotSpot,字串常量池的字串被儲存在永久代中,因此可能導致一系列的效能問題和記憶體溢位錯誤。在JDK8中,字串常量池中只儲存字串的引用。


8、JMM在初始化堆記憶體時,新生代與老年代的預設比例是多少?

永久代不屬於堆記憶體,堆記憶體只包含新生代和老年代。

預設的,新生代 ( Young ) 與老年代 ( Old ) 的比例的值為 1:2 ( 該值可以通過引數 –XX:NewRatio 來指定 ),即:新生代 ( Young ) = 1/3 的堆空間大小。
老年代 ( Old ) = 2/3 的堆空間大小。其中,新生代 ( Young ) 被細分為 Eden 和 兩個 Survivor 區域,這兩個 Survivor 區域分別被命名為 from 和 to,以示區分。
預設的,Edem : from : to = 8 : 1 : 1 ( 可以通過引數 –XX:SurvivorRatio 來設定 ),即: Eden = 8/10 的新生代空間大小,from = to = 1/10 的新生代空間大小。
‍JVM 每次只會使用 Eden 和其中的一塊 Survivor 區域來為物件服務,所以無論什麼時候,總是有一塊 Survivor 區域是空閒著的。
因此,新生代實際可用的記憶體空間為 9/10 ( 即90% )的新生代空間。

  • Java記憶體模型的描述?

9、Spring中控制反轉定義?相比於建立物件的好處?AOP程式設計的優點?

友情連結:三大框架的原理及優缺點

原來我們的程式我們控制的是具體的實現,寫程式直接寫實現,現在我們控制的是它的介面它的抽象,原來我們依賴的是它的實現,現在我們依賴的是它的抽象。從具體的實現反轉到抽象的概念上,我們針對的是介面程式設計。

1)降低元件之間的耦合度,實現軟體各層之間的解耦。
Controller——>Service——>DAO
2)可以使用容器提供的眾多服務,如:事務管理服務、訊息服務等等。當我們使用容器管理事務時,開發人員就不再需要手工控制事務.也不需處理複雜的事務傳播。
3)容器提供單例模式支援,開發人員不再需要自己編寫實現程式碼。
4)容器提供了AOP技術,利用它很容易實現如許可權攔截、執行期監控等功能。
5)容器提供的眾多輔作類,使用這些類能夠加快應用的開發,如: JdbcTemplate、 HibernateTemplate。
6)Spring對於主流的應用框架提供了整合支援,如:整合Hibernate、JPA、Struts等,這樣更便於應用的開發。
7) 使用spring容器可以提供的服務:事務管理服務,JMS服務,Spring Core核心服務,持久化服務等。
8)如果使用Spring, 我們就不再需要手工控制事務,例如在Hibernate中控制事務的語句 session.beginTransaction();session.getTransaction().commit();
9)使用Spring,不再需要我們處理複雜的事務傳播行為。


10、SpringMVC中動態代理的實現機制,原始碼?

友情連結:Spring AOP動態代理原理與實現方式 (轉)

友情連結:Java的動態代理機制和Spring的實現方式

友情連結:Java中動態代理實現機制


11、讀過哪些原始碼,請詳細描述一個你最熟悉的?(我回答ArrayList)

12、JVM虛擬機器?請詳細描述?

13、Java GC回收機制?請詳細描述?

14、問了兩道智力題!!!!!

(1)有8個產品,其中有一個次品(有可能偏重,有可能偏輕),那麼如何用天平秤三次找出那個次品?

(2)忘記了。。。。關於買賣問題

15、看過GitHub上的開放原始碼嗎(比如阿里,騰訊優秀團隊的)?

16、使用過哪些程式碼管理工具?(Git,Maven)熟練使用嗎?會不會使用GitHub上傳程式碼?

17、使用過哪些寫程式碼的工具?(Myeclipse和IDE),列出你常用的快捷鍵?

18、學習程式設計的方法、渠道?(看部落格,網站)?上哪些網站?

19、說說自己的優缺點?學習時間的分配?

20、漏了一個問題,怎麼實現讓兩個執行緒交替執行?(用程式碼實現?)

一般來說執行緒鎖可以用:Synchronized、Lock。
這個題目的難點不在於同步塊,而在於怎麼樣設計這個兩個執行緒的交替實現。由於執行緒爭用cpu的隨機性,就需要A線,B執行緒執行,在B執行完一次進入等待之前喚醒A,如此往復,那麼這裡就要用上notify和wait了。

public class Thread1 {  
    public static void main(String args[]) {  
        final Bussiness business = new Bussiness();  
        Thread a=new Thread(new Runnable(){  
            @Override  
            public void run(){  
                business.SubThread();  
            }  
        });  
        Thread b=new Thread((new Runnable() {  
            @Override  
            public void run() {  
                business.MainThread();  
            }  
        }));  
        a.start();  
        b.start();  
    }  
}  



class Bussiness {  
    private static Object LOCK = new Object();  
    volatile boolean bShouldSub = true;//這裡相當於定義了控制該誰執行的一個訊號燈  

    public void MainThread() {  
        for (int i = 0; i < 50; i++) {  
            synchronized (LOCK) {//notify和wait的物件一定要和synchronized的物件保持一致  
                for (int j = 0; j < 10; j++) {  
                    System.out.println(Thread.currentThread().getName() + "+MainThread:i=" + i + ",j=" + j);  
                }  
                if (bShouldSub) {  
                    bShouldSub = false;  
                    LOCK.notify();  
                    if(i<49){  
                        try {  
                            LOCK.wait();  
                        }catch (InterruptedException e) {  
                            // TODO Auto-generatedcatch block  
                            e.printStackTrace();  
                        }  
                    }  
                }  
            }  
        }  
    }  


    public void SubThread() {  
        for (int i = 0; i < 50; i++) {  
            synchronized (LOCK){  
                for (int j = 0; j < 5; j++) {  
                    System.out.println(Thread.currentThread().getName() + "+SubThread:i=" + i + ",j=" + j);  
                }  
                if (!bShouldSub) {  
                    bShouldSub = true;  
                    LOCK.notify();  
                    if(i<49){  
                        try {  
                            LOCK.wait();  
                        } catch (InterruptedException e) {  
                            // TODO Auto-generatedcatch block  
                            e.printStackTrace();  
                        }  
                    }  

                }  
            }  
        }  
    }  

}複製程式碼

各種容器的初始化長度是多少?

使用ArrayList初始化時注意事項?(自動擴充機制方面,原理實現)?

好了,一面到此結束,歷時一個半小時,淚崩,懵逼!(關鍵下午還有課!!!遲到了!!!)

總結一點,閱讀原始碼很重要!(Spring+SpringMVC+Mybatis)


上面題目的部分答案,歡迎前往歷年阿里面試題彙總(2017年不斷更新中)各大公司Java後端開發面試題總結查閱



更多內容,可關注我的個人公眾號

相關文章