2019年末尾總結面試常問的基礎22道Java面試題,值得收藏學習!

2019年末尾總結面試常問的基礎22道Java面試題,值得收藏學習!

1)集合類:List和Set比較,各自的子類比較(ArrayList,Vector,LinkedList;HashSet,TreeSet)

List:元素是有順序的,元素可以重複因爲每個元素有自己的角標(索引)
  |-- ArrayList:底層是數組結構,特點是:查詢很快,增刪稍微慢點,線程不同步:A線程將元素放在索引0位置,CPU調度線程A停止,B運行,也將元素放在索引0位置,當A和B同時運行的時候Size就編程了2.
  |-- LinkedList:底層使用的是鏈表數據結構,特點是:增刪很快,查詢慢。線程不安全,線程安全問題是由多個線程同時寫或同時讀寫同一個資源造成的。
  |--Vector:底層是數組數據結構,線程同步,Vector的方法前面加了synchronized關鍵字,被ArrayList代替了,現在用的只有他的枚舉。

Set:元素是無序的,且不可以重複(存入和取出的順序不一定一致),線程不同步。set底層是使用Map實現的,故可以通過ConcurrentHashMap的方式變通實現線程安全的Set。
|--HashSet:底層是哈希表數據結構。根據hashCode和equals方法來確定元素的唯一性。
hashCode和equals:作用一樣,都是用來比較兩個對象是否相等一致。
equals比較的比較全面,而利用hashCode()進行對比,則只要生成一個hash值進行比較久可以了,效率高。
equal()相等的兩個對象他們的hashCode()肯定相等,也就是equal()是絕對可靠的。
hashCode()相等的兩個對象他們的equal()不一定相等,hashCode()不是絕對可靠的。

Map:這個集合是存儲鍵值對的,一對一對往裏存,而且要確保鍵的唯一性(01,張三)這樣的形式打印出來就是  01=張三
|--HashTable:底層是哈希表數據結構,不可以存入null鍵和null值,該集合線程是同步的,效率比較低。出現於JDK1.0。線程安全,使用synchronized鎖住整張Hash表實現線程安全,即每次鎖住整張表讓線程獨佔。
|--HashMap:底層是哈希表數據結構,可以存入null鍵和null值,線程不同步,效率較高,代替了HashTable,出現於JDK 1.2
|--TreeMap:底層是二叉樹數據結構,線程不同步,可以用於對map集合中的鍵進行排序
ConcurrentHashMap:線程安全,允許多個修改操作併發進行,其關鍵在於使用了鎖分離技術,它使用了多個鎖來控制對hash表的不同部分進行的修改。ConcurrentHashMap內部使用段(Segment)來表示這些不同的部分,每個段其實就是一個小的Hashtable,它們有自己的鎖。只要多個修改操作發生在不同的段上,它們就可以併發進行。
當兩個對象需要對比的時候,首先用hashCode()去對比,如果不一樣,則表示這兩個對象肯定不相等(也就不用再比較equal(0)了),如果hashCode()相同,再比較equal(),如果equal()相同,那兩個對象就是相同的。
|--TreeSet:可以對Set集合中的元素進行排序(自然循序),底層的數據結構是二叉樹,

2)HashMap的底層實現,之後會問ConcurrentHashMap的底層實現

HashMap實際上是一個“鏈表散列”的數據結構,即數組和鏈表的結合體。允許使用null值和null鍵。

HashMap底層就是一個數組結構,數組中的每一項又是一個鏈表。當新建一個HashMap的時候,就會初始化一個數組。

HashMap是基於hash算法實現的,通過put(key,value)存儲對象到HashMap中,也可以通過get(key)從HashMap中獲取對象。

當我們使用put的時候,首先HashMap會對key的hashCode()的值進行hash計算,根據hash值得到這個元素在數組中的位置,將元素存儲在該位置的鏈表上。
當我們使用get的時候,首先HashMap會對key的hashCode()的值進行hash計算,根據hash值得到這個元素在數組中的位置,將元素從該位置上的鏈表中取出

當多線程的情況下,可能產生條件競爭。當重新調整HashMap大小的時候,確實存在條件競爭,如果兩個線程都發現HashMap需要重新調整大小了,
它們會同時試着調整大小。在調整大小的過程中,存儲在鏈表中的元素的次序會反過來,因爲移動到新的數組位置的時候,
HashMap並不會將元素放在LinkedList的尾部,而是放在頭部,這是爲了避免尾部遍歷(tail traversing)。如果條件競爭發生了,那麼就死循環了

  • ConcurrentHashMap基於雙數組和鏈表的Map接口的同步實現 
  • ConcurrentHashMap中元素的key是唯一的、value值可重複 
  • ConcurrentHashMap不允許使用null值和null鍵 
  • ConcurrentHashMap是無序的

爲什麼使用ConcurrentHashMap:
我們都知道HashMap是非線程安全的,當我們只有一個線程在使用HashMap的時候,自然不會有問題,但如果涉及到多個線程,並且有讀有寫的過程中,HashMap就會fail-fast。要解決HashMap同步的問題,我們的解決方案有:Hashtable 、Collections.synchronizedMap(hashMap) 
這兩種方式基本都是對整個hash表結構加上同步鎖,這樣在鎖表的期間,別的線程就需要等待了,無疑性能不高,所以我們引入ConcurrentHashMap,既能同步又能多線程訪問

ConcurrentHashMap的數據結構:
ConcurrentHashMap的數據結構爲一個Segment數組,Segment的數據結構爲HashEntry的數組,而HashEntry存的是我們的鍵值對,可以構成鏈表。可以簡單的理解爲數組裏裝的是HashMap

3)如何實現HashMap順序存儲:可以參考LinkedHashMap的底層實現

LinkedHashMap底層使用哈希表與雙向鏈表來保存所有元素,它維護着一個運行於所有條目的雙向鏈表(如果學過雙向鏈表的同學會更好的理解它的源代碼),此鏈表定義了迭代順序,該迭代順序可以是插入順序或者是訪問順序 

  1. 按插入順序的鏈表:在LinkedHashMap調用get方法後,輸出的順序和輸入時的相同,這就是按插入順序的鏈表,默認是按插入順序排序
  2. 按訪問順序的鏈表:在LinkedHashMap調用get方法後,會將這次訪問的元素移至鏈表尾部,不斷訪問可以形成按訪問順序排序的鏈表。簡單的說,按最近最少訪問的元素進行排序(類似LRU算法)

4)String,StringBuffer和StringBuilder的區別

運行速度快慢爲:StringBuilder > StringBuffer > String

String最慢的原因:
String爲字符串常量,而StringBuilder和StringBuffer均爲字符串變量,即String對象一旦創建之後該對象是不可更改的,但後兩者的對象是變量,是可以更改的。

  • String:適用於少量的字符串操作的情況,
  • StringBuilder:適用於單線程下在字符緩衝區進行大量操作的情況(線程不安全)
  • StringBuffer:適用多線程下在字符緩衝區進行大量操作的情況(線程安全)

5)Object的方法有哪些:比如有wait方法,爲什麼會有wait、notify、notifuAll

  1. 使用wait()、notify()和notifyAll()時需要首先對調用對象加鎖
  2. 調用wait()方法後,線程狀態會從RUNNING變爲WAITING,並將當線程加入到lock對象的等待隊列中
  3. 調用notify()或者notifyAll()方法後,等待在lock對象的等待隊列的線程不會馬上從wait()方法返回,必須要等到調用notify()或者notifyAll()方法的線程將lock鎖釋放,等待線程纔有機會從等待隊列返回。這裏只是有機會,因爲鎖釋放後,等待線程會出現競爭,只有競爭到該鎖的線程纔會從wait()方法返回,其他的線程只能繼續等待
  4. notify()方法將等待隊列中的一個線程移到lock對象的同步隊列,notifyAll()方法則是將等待隊列中所有線程移到lock對象的同步隊列,被移動的線程的狀態由WAITING變爲BLOCKED
  5. wait()方法上等待鎖,可以通過wait(long timeout)設置等待的超時時間

6)wait和sleep的區別,必須理解

sleep方法屬於線程,wait方法屬於對象
sleep休眠當前線程,不會釋放對象鎖,wait使當前線程進入等待狀態,釋放對象鎖,只有針對此對象調用notify()方法(且共享對象資源釋放)後本線程纔會繼續執行

7)JVM的內存結構,JVM的算法

JVM內存結構主要有三大塊:堆內存、方法區和棧,幾乎所有的對象實例都存放在堆裏,如果在堆中沒有內存完成實例分配,並且堆也無法再擴展時,將會拋出OutOfMemoryError異常。
方法區用於存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯後的代碼等數據,當方法區無法滿足內存分配需求時,將拋出OutOfMemoryError異常。
每個方法被執行的時候都會同時創建一個棧幀(Stack Frame)用於存儲局部變量表、操作棧、動態鏈接、方法出口等信息。
每一個方法被調用直至執行完成的過程,就對應着一個棧幀在虛擬機棧中從入棧到出棧的過程。 
如果線程請求的棧深度大於虛擬機所允許的深度,將拋出StackOverflowError異常。

8)強引用,軟引用和弱引用的區別

強引用:
以前我們使用的大部分引用實際上都是強引用,這是使用最普遍的引用。如果一個對象具有強引用,那就類似於必不可少的生活用品,垃圾回收器絕不會回收它。
當內存空間不足,Java虛擬機寧願拋出OutOfMemoryError錯誤,使程序異常終止,也不會靠隨意回收具有強引用的對象來解決內存不足問題。 

軟引用:
如果一個對象只具有軟引用,那就類似於可有可物的生活用品。如果內存空間足夠,垃圾回收器就不會回收它,如果內存空間不足了,就會回收這些對象的內存

弱引用:
弱引用與軟引用的區別在於:只具有弱引用的對象擁有更短暫的生命週期。
在垃圾回收器線程掃描它所管轄的內存區域的過程中,一旦發現了只具有弱引用的對象,不管當前內存空間足夠與否,都會回收它的內存

總結:

  • 強引用:String str = “abc”; list.add(str); 
  • 軟引用:如果弱引用對象回收完之後,內存還是報警,繼續回收軟引用對象 
  • 弱引用:如果虛引用對象回收完之後,內存還是報警,繼續回收弱引用對象 
  • 虛引用:虛擬機的內存不夠使用,開始報警,這時候垃圾回收機制開始執行System.gc(); String s = “abc”;如果沒有對象回收了, 就回收沒虛引用的對象

9)數組在內存中如何分配

當一個對象使用關鍵字“new”創建時,會在堆上分配內存空間,然後返回對象的引用,這對數組來說也是一樣的,因爲數組也是一個對象
簡單的值類型的數組,每個數組成員是一個引用(指針),引用到棧上的空間

10)用過哪些設計模式,手寫一個(除單例)

1.懶漢模式

    public class SingletonDemo {
        private static SingletonDemo instance;
        private SingletonDemo(){}
        public static SingletonDemo getInstance(){
            if(instance==null){
                instance=new SingletonDemo();
            }
            return instance;
        }
    }

2.餓漢模式

    public class SingletonDemo {
        private static SingletonDemo instance=new SingletonDemo();
        private SingletonDemo(){}
        public static SingletonDemo getInstance(){
            return instance;
        }
    }

3.簡單工廠模式

麪條工廠:

    public abstract class INoodles {
        /**
         * 描述每種麪條啥樣的
         */
        public abstract void desc();
    }

先來一份蘭州拉麪(具體的產品類):

    public class LzNoodles extends INoodles {
        @Override
        public void desc() {
            System.out.println("蘭州拉麪 上海的好貴 家裏才5 6塊錢一碗");
        }
    }

程序員加班必備也要吃泡麪(具體的產品類):

    public class PaoNoodles extends INoodles {
        @Override
        public void desc() {
            System.out.println("泡麪好吃 可不要貪杯");
        }
    }

準備工作做完了,我們來到一家“簡單面館”(簡單工廠類),菜單如下:

    public class SimpleNoodlesFactory {
        public static final int TYPE_LZ = 1;//蘭州拉麪
        public static final int TYPE_PM = 2;//泡麪
        public static INoodles createNoodles(int type) {
            switch (type) {
                case TYPE_LZ:
                    return new LzNoodles();
                case TYPE_PM:
                    return new PaoNoodles();
                default:
                    return new PaoNoodles();
            }
        }
        /**
         * 簡單工廠模式
         */
        void creat(){
            INoodles noodles = SimpleNoodlesFactory.createNoodles(SimpleNoodlesFactory.TYPE_PM);
                noodles.desc();
        }
    } 

11)springmvc的核心是什麼,請求的流程是怎麼處理的,控制反轉怎麼實現的aop和ioc

流程:用戶發送請求給服務器。url:user.do--->Dispatchservlet處理-->DispatchServlet通過HandleMapping調用這個url對應的Controller
Controller執行完畢後,如果返回字符串,則ViewResolver將字符串轉化成相應的視圖對象;如果返回ModelAndView對象,該對象本身就包含了視圖對象信息。
DispatchServlet將執視圖對象中的數據,輸出給服務器並呈現給客戶

IOC控制反轉:典型的工廠模式,就是具有依賴注入功能的容器,是可以創建對象的容器,IOC容器負責實例化、定位、配置應用程序中的對象及建立這些對象間的依賴。
通常new一個實例,控制權由程序員控制,而"控制反轉"是指new實例工作不由程序員來做而是交給Spring容器來做。。在Spring中BeanFactory是IOC容器的實際代表者

AOP依賴注入:典型的代理模式,面向切面編程將程序中的交叉業務邏輯(比如安全,日誌,事務),封裝成一個切面,然後注入到目標業務邏輯中去。

aop框架具有的兩個特徵:

  • 各個步驟之間的良好隔離性
  • 源代碼無關性 

12)mybatis如何處理結果集:反射,建議看看源碼

通過在mapper配置文件裏配置的屬性對照反射進對象裏

13)java的多態表現在哪裏

多態是同一個行爲具有多個不同表現形式或形態的能力。
多態就是同一個接口,使用不同的實例而執行不同操作
比如同一個打印機,可以打印黑白的紙張也可以打印彩色的,同樣是人,卻有黑人白人之分

14)接口有什麼用

接口是一種規範,在這裏舉兩個例子

  • 接口就比如KFC,你一聽KFC就知道是賣炸2019年末尾總結面試常問的基礎22道Java面試題,值得收藏學習!薯條的,他可以有不同的分店,也可以有自己的創新食品(多態),但是招牌炸2019年末尾總結面試常問的基礎22道Java面試題,值得收藏學習!2019年末尾總結面試常問的基礎22道Java面試題,值得收藏學習!肉卷、全家桶什麼的肯定會有,你不用進店看菜單就知道他有,但如果不叫KFC換成炸2019年末尾總結面試常問的基礎22道Java面試題,值得收藏學習!店你也可以吃到炸2019年末尾總結面試常問的基礎22道Java面試題,值得收藏學習!,但是你不進店看菜單你不知道他具體都賣的有哪些食品,這就是接口的好處
  • 比如電插孔,多是兩孔和三孔的那種,如果沒有這種規範那每家電器公司都來做一種插孔的話,試想一下插頭換了怎麼辦?是不是隻能買原裝的來替換了

15)說說http,https協議

http是一種超文本協議,默認端口80,以明文傳輸。
https是http協議的安全版,安全基礎是SSL,以密文傳輸

16)osi五層網絡協議

  • 應用層
  • 傳輸層
  • 網絡層
  • 數據鏈路層
  • 物理層

17)用過哪些加密算法

  • 對稱加密
  • 非對稱加密算法
  • Base64加密算法
  • MD5加密算法
  • SHA1加密算法

18)說說tcp三次握手,四次揮手

  1. 客戶端向服務器發送一個syn包,進入發送狀態
  2. 服務器收到syn包,確認客戶的syn,並向客戶端發送syn+ack包,進入接受狀態
  3. 客戶端接受的來自服務的的syn包信息,向服務的發出ack包,次數兩者進入tcp連接成功狀態

19)cookie和session的區別,分佈式環境怎麼保存用戶狀態

cookie存在客戶端,session存在服務端

分佈式Session的幾種實現方式

  1. 基於數據庫的Session共享
  2. 基於NFS共享文件系統
  3. 基於memcached 的session,如何保證 memcached 本身的高可用性?
  4. 基於resin/tomcat web容器本身的session複製機制
  5. 基於TT/Redis 或 jbosscache 進行 session 共享。
  6. 基於cookie 進行session共享(唯一值token)

20)git,svn區別

Git是分佈式的,而Svn不是分佈的
Git下載下來後,在OffLine狀態下可以看到所有的Log,SVN不可以
SVN的特點是簡單,只是需要一個放代碼的地方時用是OK的,Git的特點版本控制可以不依賴網絡做任何事情,對分支和合併有更好的支持

21)請寫一段棧溢出、堆溢出的代碼

堆溢出,死循環存值,JVM就會拋出OutOfMemoryError:java heap space異常

    public static void main(String[] args) {
        List<byte[]> list = new ArrayList<>();
        int i=0;
        while(true){
            list.add(new byte[5*1024*1024]);
            System.out.println("分配次數:"+(++i));
        }
    }
棧溢出,棧空間不足——StackOverflowError實例

    public class StackSOFTest {
        int depth = 0;
        public void sofMethod(){
            depth ++ ;
            sofMethod();
        }
        public static void main(String[] args) {
            StackSOFTest test = null;
            try {
                test = new StackSOFTest();
                test.sofMethod();
            } finally {
                System.out.println("遞歸次數:"+test.depth);
            }
        }
    }

22)ThreadLocal可以用來共享數據嗎

可以
ThreadLocal使用場合主要解決多線程中數據數據因併發產生不一致問題。ThreadLocal爲每個線程的中併發訪問的數據提供一個副本,通過訪問副本來運行業務,這樣的結果是耗費了內存,單大大減少了線程同步所帶來性能消耗,也減少了線程併發控制的複雜度。
ThreadLocal和Synchonized都用於解決多線程併發訪問。但是ThreadLocal與synchronized有本質的區別。synchronized是利用鎖的機制,使變量或代碼塊在某一時該只能被一個線程訪問。而ThreadLocal爲每一個線程都提供了變量的副本,使得每個線程在某一時間訪問到的並不是同一個對象,這樣就隔離了多個線程對數據的數據共享。而Synchronized卻正好相反,它用於在多個線程間通信時能夠獲得數據共享。
Synchronized用於線程間的數據共享,而ThreadLocal則用於線程間的數據隔離。

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