1. 程式人生 > >三年Java軟體工程師應該掌握的技能

三年Java軟體工程師應該掌握的技能

關於專案經驗

關於專業技能
1、基本語法
static、final、transient等關鍵字的作用
foreach迴圈的原理等等

static:
1.靜態變數
2.靜態方法
3.靜態程式碼塊
final:
1.修飾類的屬性,作用:修飾靜態變數不可變,不建議修飾例項變數
2.修飾類的方法,作用:可以被繼承,但不能重寫
3.修飾類,作用:類不可以被繼承
transient:
1.一旦變數被transient修飾,變數將不再是物件持久化(序列化)的一部分,該變數內容在序列化後沒有值。
2.transient關鍵字只能修飾變數,而不能修飾方法和類。注意,本地變數是不能被transient關鍵字修飾的。變數如果是使用者自定義類變數,則該類需要實現Serializable介面。
3.被transient關鍵字修飾的變數不再能被序列化,一個靜態變數不管是否被transient修飾,均不能被序列化。

serialVersionUID的作用:
如果沒有明確指定serialVersionUID,序列化的時候會根據欄位和特定的演算法生成一個serialVersionUID,當屬性有變化時這個id發生了變化,所以反序列化的時候
就會失敗。丟擲“本地classd的唯一id和流中class的唯一id不匹配”。

2.集合
List、Map、Set,問的是各種實現類的底層實現原理,實現類的優缺點。
集合要掌握的是ArrayList、LinkedList、Hashtable、HashMap、ConcurrentHashMap、HashSet的實現原理,
能流利作答,當然能掌握CopyOnWrite容器和Queue是再好不過的

ArrayList實現了可變大小的陣列。它允許所有元素,包括null。ArrayList沒有同步。
Hashtable繼承Map介面,Hashtable是同步的。實現一個key-value對映的雜湊表。任何非空(non-null)的物件都可作為key或者value。
HashMap和Hashtable類似,不同之處在於HashMap是非同步的,並且允許null,即null value和null key。
HashMap解析:http://zhangshixi.iteye.com/blog/672697
ArrayList解析:http://www.cnblogs.com/ITtangtang/p/3948555.html


ArrayList原始碼中:private transient E[] elementData; //屬性存放資料
ArrayList是會開闢多餘空間來儲存資料的,而系列化和反序列化這些沒有存放資料的空間是要消耗更多資源的,
所以ArrayList的陣列就宣告為transient,自己實現write/readObject方法,僅僅系列化已經存放的資料。

ConcurrentHashMap的問題在面試中問得特別多
ConcurrentHashMap與HashTable的區別主要是鎖的粒度不同,HashTable當寫資料時,鎖住整個Hash表,而ConcurrentHashMap是所Hash表的段(桶)

(1)ConcurrentHashMap的鎖分段技術
答:ConcurrentHashMap將Hash表分成多個段(預設16個段),則有更新資料時,大部分是鎖段,不鎖整張Hash表,提高了效能
每個segment則是一個傳統意義上的hashtable

(2)ConcurrentHashMap的讀是否要加鎖,為什麼
答:讀大部分情況下不加鎖。當在get的時候,經過Hash,找到Hash表中的段(桶),再找到key在該段對應的index值,後會進行遍歷資料,詳見程式碼readValueUnderLock():
在判斷存在hash值的節點,且key也存在,而值為null,則需要重新上鎖再讀。
這裡當v為空時,可能是一個執行緒正在改變節點,而之前的get操作都未進行鎖定,根據bernstein條件,讀後寫或寫後讀都會引起資料的不一致,
所以這裡要對這個e重新上鎖再讀一遍,以保證得到的是正確值
V get(Object key, int hash) {
if (count != 0) { // read-volatile
HashEntry e = getFirst(hash);
while (e != null) {
if (e.hash == hash && key.equals(e.key)) {
V v = e.value;
if (v != null)
return v;
return readValueUnderLock(e); // recheck
}
e = e.next;
}
}
return null;
}
V readValueUnderLock(HashEntry e) {
lock();
try {
return e.value;
} finally {
unlock();
}
}
(3)ConcurrentHashMap的迭代器是強一致性的迭代器還是弱一致性的迭代器
答:弱一致性的迭代器
public static void main(String[] args) {

    Map<String, String> testMap = new ConcurrentHashMap<String, String>();

    testMap.put("pengjie1", "pengjie test 1");
    testMap.put("pengjie2", "pengjie test 2");
    testMap.put("pengjie3", "pengjie test 3");
    testMap.put("pengjie4", "pengjie test 4");
    testMap.put("pengjie5", "pengjie test 5");
    testMap.put("pengjie6", "pengjie test 6");
    testMap.put("pengjie7", "pengjie test 7");

    Collection<String> values  = testMap.values();

    Iterator<String> iterator = values.iterator();

    while (iterator.hasNext()) {
        String name = (String) iterator.next();
        System.out.println("name :"+name);

        testMap.remove("pengjie1");//pengjie1被刪除,但不影響執行
    }
    System.out.print("Map size:"+testMap.size());
}

結果:
name :pengjie test 7
name :pengjie test 2
name :pengjie test 5
name :pengjie test 3
name :pengjie test 6
name :pengjie test 4
Map size:6

3、設計模式
http://www.cnblogs.com/maowang1991/archive/2013/04/15/3023236.html
簡單工廠模式、靜態工廠方法模式、抽象工廠模式、單例模式、裝飾模式、代理模式、觀察者模式
面試中關於設計模式的問答主要是三個方向:
(1)你的專案中用到了哪些設計模式,如何使用
(2)知道常用設計模式的優缺點
(3)能畫出常用設計模式的UML圖

裝飾模式:顧名思義,裝飾模式就是給一個物件增加一些新的功能,而且是動態的,要求裝飾物件和被裝飾物件實現同一個介面,裝飾物件持有被裝飾物件的例項
代理模式:就是多一個代理類出來,替原物件進行一些操作,比如我們在租房子的時候回去找中介,為什麼呢?因為你對該地區房屋的資訊掌握的不夠全面,希望找一個更熟悉的人去幫你做
裝飾模式與代理模式的區別:裝飾模式持有對被裝飾物件的例項,而代理模式沒有。
裝飾模式是對被裝飾物件的增強。代理模式是對被代理類的限制
當使用代理模式的時候,我們常常在一個代理類中建立一個物件的例項。
當我們使用裝飾器模式的時候,我們通常的做法是將原始物件作為一個引數傳給裝飾者的構造器。

4、多執行緒
這也是必問的一塊了。因為三年工作經驗,所以基本上不會再問你怎麼實現多執行緒了,
會問得深入一些比如說Thread和Runnable的區別和聯絡、多次start一個執行緒會怎麼樣、執行緒有哪些狀態。
(一個Thread的例項一旦呼叫start()方法,這個例項的started標記就標記為true)
當然這只是最基本的,出乎意料地,幾次面試幾乎都被同時問到了一個問題,問法不盡相同,總結起來是這麼一個意思:
問題:
假如有Thread1、Thread2、Thread3、Thread4四條執行緒分別統計C、D、E、F四個盤的大小,
所有執行緒都統計完畢交給Thread5執行緒去做彙總,應當如何實現?

5、JDK原始碼
要想拿高工資,JDK原始碼不可不讀。上面的內容可能還和具體場景聯絡起來,JDK原始碼就是實打實地看你平時是不是愛鑽研了。
LZ面試過程中被問了不少JDK原始碼的問題,其中最刁鑽的一個問了LZ,String的hashCode()方法是怎麼實現的,幸好LZ平時String原始碼看得多,
答了個大概。JDK原始碼其實沒什麼好總結的,純粹看個人,總結一下比較重要的原始碼:
(1)List、Map、Set實現類的原始碼
(2)ReentrantLock、AQS的原始碼
(3)AtomicInteger的實現原理,主要能說清楚CAS機制並且AtomicInteger是如何利用CAS機制實現的
(4)執行緒池的實現原理
(5)Object類中的方法以及每個方法的作用
這些其實要求蠻高的,LZ去年一整年基本把JDK中重要類的原始碼研究了個遍,真的花費時間、花費精力,當然回頭看,是值得的—-不僅僅是為了應付面試。

AtomicInteger的實現原理:

    private volatile int value;//取記憶體中的最新值

public final int incrementAndGet() {
    for (;;) {
        int current = get();
        int next = current + 1;
        //關鍵函式,將current與記憶體中的值進行比較,若相同,則更新,並返回true;
        //若記憶體中的值已經被修改,則返回false,進入下一次迴圈
        if (compareAndSet(current, next))
            return next;
    }
}

多執行緒分析:
在使用中我們一般使用Executors類的靜態方法來建立執行緒池,除非我們對於執行緒池非常理解才能自己去靈活的規劃執行緒池類(可以用來繼承ThreadPoolExecutor)
1:核心執行緒:簡單來講就是執行緒池中能否允許同時併發執行的執行緒的數量
2:執行緒池大小:執行緒池中最多能夠容納的執行緒的數量。
3:佇列:對提交過來的任務的處理模式。
如果佇列發過來的任務,發現執行緒池中正在執行的執行緒的數量小於核心執行緒,則立即建立新的執行緒,無需進入佇列等待。
如果正在執行的執行緒等於或者大於核心執行緒,則必須參考提交的任務能否加入佇列中去
任務進入佇列總共只有三種情況:
1.能加入,且佇列無界,則最多執行核心執行緒池數 ,最大執行緒池數沒有作用
2.能加入,且佇列有界,則佇列滿後,創新新的執行緒執行任務,超過最大執行緒池數後拒絕任務
3.不能加入,直接提交到執行緒池。建立新的執行緒執行任務,超過最大執行緒池數後拒絕任務

參考多執行緒分析:http://my.oschina.net/u/1398304/blog/376827
佇列的三種策略:
SynchronousQueue 直接提交,也就是上面講到的所有任務不進入佇列去等待。此時小於核心執行緒就增加,多於或等於核心執行緒數時,還是增加執行緒,最大為執行緒池中的最大允許。超出就拒絕。
LinkedBlockingQueue 無界佇列 此時超過核心執行緒後的任務全部加入佇列等待,系統最多隻能執行核心執行緒數量的執行緒。這種方法相當於控制了併發的執行緒數量。
ArrayBlockingQueue 有界佇列 此時超過核心執行緒後的任務先加入佇列等待,超出佇列範圍後的任務就生成執行緒,但建立的執行緒最多不超過執行緒池的最大允許值。

1、執行緒池剛建立時,裡面沒有一個執行緒。任務佇列是作為引數傳進來的。不過,就算佇列裡面有任務,執行緒池也不會馬上執行它們。
2、當呼叫 execute() 方法新增一個任務時,執行緒池會做如下判斷:
a. 如果正在執行的執行緒數量小於 corePoolSize,那麼馬上建立執行緒執行這個任務;
b. 如果正在執行的執行緒數量大於或等於 corePoolSize,那麼將這個任務放入佇列。
c. 如果這時候佇列滿了,而且正在執行的執行緒數量小於 maximumPoolSize,那麼還是要建立執行緒執行這個任務;
d. 如果佇列滿了,而且正在執行的執行緒數量大於或等於 maximumPoolSize,那麼執行緒池會丟擲異常,告訴呼叫者“我不能再接受任務了”。
3、當一個執行緒完成任務時,它會從佇列中取下一個任務來執行。
4、當一個執行緒無事可做,超過一定的時間(keepAliveTime)時,執行緒池會判斷,如果當前執行的執行緒數大於 corePoolSize,那麼這個執行緒就被停掉。所以執行緒池的所有任務完成後,它最終會收縮到 corePoolSize 的大小。
這個過程說明,並不是先加入任務就一定會先執行。假設佇列大小為 4,corePoolSize為2,maximumPoolSize為6,
那麼當加入15個任務時,執行的順序類似這樣:首先執行任務 1、2,然後任務3~6被放入佇列。
這時候佇列滿了,任務7、8、9、10 會被馬上執行,而任務 11~15 則會丟擲異常。
最終順序是:1、2、7、8、9、10、3、4、5、6。當然這個過程是針對指定大小的ArrayBlockingQueue來說,
如果是LinkedBlockingQueue,因為該佇列無大小限制,所以不存在上述問題。

6、框架
老生常談,面試必問的東西。一般來說會問你一下你們專案中使用的框架,然後給你一些場景問你用框架怎麼做,
比如我想要在Spring初始化bean的時候做一些事情該怎麼做、想要在bean銷燬的時候做一些事情該怎麼做、MyBatis中$和#的區別等等,這些都比較實際了,平時積累得好、有多學習框架的使用細節自然都不成問題。
如果上面你的問題答得好,面試官往往會深入地問一些框架的實現原理。
問得最多的就是Spring AOP的實現原理,當然這個很簡單啦,兩句話就搞定的的事兒,即使你不會準備一下就好了。
LZ遇到的最變態的是讓LZ畫一下Spring的Bean工廠實現的UML圖,當然面對這樣一個有深度的問題,LZ是絕對答不出來的/(ㄒoㄒ)/~~

7、資料庫

8、資料結構和演算法分析
可以不瞭解它們的具體實現,但是要知道什麼是二叉查詢樹、什麼是平衡樹,AVL樹和紅黑樹的區別。
記得某次面試,某個面試官和我聊到了資料庫的索引,他問我:
你知道索引使用的是哪種資料結構實現嗎?
為什麼要使用樹嗎?

9、Java虛擬機器
出乎LZ的意料,Java虛擬機器應該是很重要的一塊內容,結果在這幾家公司中被問到的概率幾乎為0。

10、Web方面的一些問題
Java主要面向Web端,因此Web的一些問題也是必問的。LZ碰到過問得最多的兩個問題是:
談談分散式Session的幾種實現方式
常用的四種能答出來自然是讓面試官非常滿意的,另外一個常問的問題是:
講一下Session和Cookie的區別和聯絡以及Session的實現原理
這兩個問題之外,web.xml裡面的內容是重點,Filter、Servlet、Listener,不說對它們的實現原理一清二楚吧,至少能對它們的使用知根知底。
另外,一些細節的方面比如get/post的區別、forward/重定向的區別、HTTPS的實現原理也都可能會被考察到。

關於HR面試
這輪的面試也必須重視起來,HR面試主要問的是幾點:
1、簡歷中寫的過去工作經歷的離職原因
2、當前公司薪資待遇
3、期望能到怎樣的一家公司
4、個人未來的發展方向