Java面試准備(一)


工作之后的學習都是在業務的驅動下進行的,對於以前的基礎知識生疏了許多,也不知從何開始,借助別人面試分享的經驗,接下去准備回顧一波。

Java基礎篇

 

MAP集合類問題:

1.HashMap的源碼,實現原理,JDK1.8中對HashMap做了怎么樣的優化。

HashMap是基於哈希表實現的,每一個元素是一個key-value對,其內部通過單鏈表解決沖突問題,容量不足(超過了閥值)時,同樣會自動增長。   在jdk1.8里  加入了紅黑樹的實現,當鏈表的長度大於8時,轉換為紅黑樹的結構。

2.HashMap是怎么樣進行擴容的,為什么都是2的N次冪的大小。

首先,length為2的整數次冪的話,h&(length-1)就相當於對length取模,這樣便保證了散列的均勻,同時也提升了效率;其次,length為2的整數次冪的話,為偶數,這樣length-1為奇數,奇數的最后一位是1,這樣便保證了h&(length-1)的最后一位可能為0,也可能為1(這取決於h的值),即與后的結果可能為偶數,也可能為奇數,這樣便可以保證散列的均勻性,而如果length為奇數的話,很明顯length-1為偶數,它的最后一位是0,這樣h&(length-1)的最后一位肯定為0,即只能為偶數,這樣任何hash值都只會被散列到數組的偶數下標位置上,這便浪費了近一半的空間,因此,length取2的整數次冪,是為了使不同hash值發生碰撞的概率較小,這樣就能使元素在哈希表中均勻地散列。

3.HashMap,HashTable,ConcurrentHashMap區別。

首先講講HashMap和HashTable的區別,最重要的兩個區別特性是:a.HashMap是非線程安全的,HashTable是線程安全的。b.HashMap的鍵和值都允許有null存在,而HashTable則都不行。c.一般線程安全沒有太大的要求和考慮哈希碼效率問題時,所以一般HashMap。在同等考慮線程安全的情況下,concurrentHashMap就是HashMap的一個比較好的替代了。HashMap是非線程安全的,只是用於單線程環境下,多線程環境下可以采用concurrent並發包下的concurrentHashMap。

4.極高並發下HashTable 和ConcurrentHashMap哪個性能好,為什么如何實現的。

區別:

HashTable使用一把鎖處理並發問題,當有多個線程訪問時,需要多個線程競爭一把鎖,導致阻塞

ConcurrentHashMap則使用分段,相當於把一個HashMap分成多個,然后每個部分分配一把鎖,這樣就可以支持多線程訪問

5.HashMap在高並發下如果沒有處理線程安全會有怎么樣的安全隱患,具體表現是什么。

a.HashMap在多線程put后可能導致get無限循環 。b.多線程put的時候可能導致元素丟失。

對於安全使用hash類的建議:使用Hashtable 類,Hashtable 是線程安全的;
使用並發包下的java.util.concurrent.ConcurrentHashMap,ConcurrentHashMap實現了更高級的線程安全;
或者使用synchronizedMap() 同步方法包裝 HashMap object,得到線程安全的Map,並在此Map上進行操作。

java基礎問題 

6.java中四種類型的修飾符的限制范圍。

都可以用來修飾類,方法,字段。

                    類內     包內     子類     包外

public:       √           √           √           √

projected:  √           √           √

default:      √           √

private:      √

7.Object類中的方法

clone() ,hascode(),equals(),toString(),getClass(),wait(),wait(),wait(long,int),notify(),notifyAll(),finalize。

8.接口和抽象類的區別,注意jdk8的接口可以有實現。

從現實的角度去理解, 接口表示這個對象能做什么,抽象類表示這個對象是什么。比如男人和女人,是兩種類別的東西,由男人女人可以,延伸一些帶品質,帶職業的人,這時候通常用抽象類去描述。如果描述一個人有多種動作,吃、喝、玩、樂,則就是用接口去實現,實現了就代表有這個行為。

a. 接口是抽象類的變體,接口中所有的方法都是抽象的。而抽象類是聲明方法的存在而不去實現它的類。
b. 接口可以多繼承,抽象類不行
c.接口定義方法,不能實現,而抽象類可以實現部分方法。
d. 接口中基本數據類型為static 而抽類象不是的。

一個類可以繼承一個抽象類,但是可以實現多個接口。抽象類的功能比接口強大,但是代價比較高。

9.動態代理的兩種方式,以及區別。

jdk動態代理和cglib動態代理。jdk動態代理是由java內部的反射機制來實現的,cglib動態代理底層則是借助asm來實現的。總的來說,反射機制在生成類的過程中比較高效,而asm在生成類之后的相關執行過程中比較高效(可以通過將asm生成的類進行緩存,這樣解決asm生成類過程低效問題)。還有一點必須注意:jdk動態代理的應用前提,必須是目標類基於統一的接口。如果沒有上述前提,jdk動態代理不能應用。由此可以看出,jdk動態代理有一定的局限性,cglib這種第三方類庫實現的動態代理應用更加廣泛,且在效率上更有優勢。。

10.Java序列化的方式。

 Java常見的序列化的方式有Java原生序列化,json序列化,fastjson序列化,protobuff序列化。

Java原生序列化方法即通過Java原生流(InputStream和OutputStream之間的轉化)的方式進行轉化。需要注意的是JavaBean實體類必須實現Serializable接口,否則無法序列化。

Json序列化一般會使用jackson包,通過ObjectMapper類來進行一些操作,比如將對象轉化為byte數組或者將json串轉化為對象。現在的大多數公司都將json作為服務器端返回的數據格式。比如調用一個服務器接口,通常的請求為xxx.json?a=xxx&b=xxx的形式。

fastjson 是由阿里巴巴開發的一個性能很好的Java 語言實現的 Json解析器和生成器。特點:速度快,測試表明fastjson具有極快的性能,超越任其他的java json parser。功能強大,完全支持java bean、集合、Map、日期、Enum,支持范型和自省。無依賴,能夠直接運行在Java SE 5.0以上版本

ProtoBuff序列化對象可以很大程度上將其壓縮,可以大大減少數據傳輸大小,提高系統性能。對於大量數據的緩存,也可以提高緩存中數據存儲量。原始的ProtoBuff需要自己寫.proto文件,通過編譯器將其轉換為java文件,顯得比較繁瑣。百度研發的jprotobuf框架將Google原始的protobuf進行了封裝,對其進行簡化,僅提供序列化和反序列化方法。其實用上也比較簡潔,通過對JavaBean中的字段進行注解就行,不需要撰寫.proto文件和實用編譯器將其生成.java文件,百度的jprotobuf都替我們做了這些事情了。

11.傳值和傳引用的區別,java是怎么樣的,有沒有傳值的引用。

    一、“傳值”傳遞的是一個值,而“傳引用”傳遞的是指向一個另一塊內存空間的地址;

    二、“傳值”實際是將一個值的拷貝傳遞至方法內部,這個值的原始數據是不會改變的,無論你內部進行的是何種操作,都不會改變這個源數據的值;而“傳引用”傳遞進去的則是指向一個對象的地址,那么在方法內部進行實際操作的時候,就很可能會改變該對象的屬性值(當然具體是否改變,還需要結合具體的業務)。

12.一個ArrayList在循環過程中刪除,會不會有問題,為什么。

 ArrayList在循環的過程中刪除及易發生錯誤,主要原因1:如果刪除的原素有相同的,則刪除第一個以后,第二個不再做刪除,看ArrayList的jdk源碼知道:刪除第一個以后,在遍歷第一個字符串時因為符合刪除條件,所以將該元素從數組中刪除,並且將后一個元素移動至當前位置,導致下一次循環遍歷時后一個字符串並沒有遍歷到,所以無法刪除。針對這種情況可以倒序刪除的方式來避免。原因2:用foreach遍歷循環,寫法是對實際的Iterable、hasNext、next方法的簡寫,問題同樣處在上文的fastRemove方法中,這里會做迭代器內部修改次數檢查,因為上面的remove(Object)方法修改了modCount的值,所以才會報出並發修改異常。要避免這種情況的出現則在使用迭代器迭代時(顯示或for-each的隱式)不要使用ArrayList的remove,改為用Iterator的remove即可。

13@transactional注解在什么情況下回失效,為什么?

下面是@Transactional注解事務的4點特性:

1、service類標簽(一般不建議在接口上)上添加@Transactional,可以將整個類納入spring事務管理,在每個業務方法執行時都會開啟一個事務,不過這些事務采用相同的管理方式。

2、@Transactional 注解只能應用到 public 可見度的方法上。 如果應用在protected、private或者 package可見度的方法上,也不會報錯,不過事務設置不會起作用。

3、默認情況下,Spring會對unchecked異常進行事務回滾;如果是checked異常則不回滾。 

4、只讀事務: 

@Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true) 
只讀標志只在事務啟動時應用,否則即使配置也會被忽略。 
啟動事務會增加線程開銷,數據庫因共享讀取而鎖定(具體跟數據庫類型和事務隔離級別有關)。通常情況下,僅是讀取數據時,不必設置只讀事務而增加額外的系統開銷。

事物的七種傳播模式:REQUIRED(默認模式)、NOT_SUPPORTED、REQUIRESNEW、MANDATORY、SUPPORTS、NEVER、NESTED。

通過了解特性后再去根據多種原因判斷@transactional注解失效的理由:

1、檢查你方法是不是public的

2、你的異常類型是不是unchecked異常 
如果我想check異常也想回滾怎么辦,注解上面寫明異常類型即可

@Transactional(rollbackFor=Exception.class) 

類似的還有norollbackFor,自定義不回滾的異常

3、數據庫引擎要支持事務,如果是MySQL,注意表要使用支持事務的引擎,比如innodb,如果是myisam,事務是不起作用的

4、是否開啟了對注解的解析

 <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>

5、spring是否掃描到你這個包,如下是掃描到org.test下面的包

<context:component-scan base-package="org.test" ></context:component-scan>

6、檢查是不是同一個類中的方法調用(如a方法調用同一個類中的b方法) 
7、異常是不是被你catch住了


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM