面試知識點總結——Java基礎
這裡總結網上各大面經上出現的題目,持續整理。
1. 九種基本資料類型的大小,以及他們的封裝類。
byte1/float4/short2/double8/int4/char2/long8/boolean
包裝類一般首字母大寫,除了Integer(int)和Character(char)。
2. Switch能否用string做參數?
Java7之前無法使用字元串,在Java7以及以後的版本中可以使用字元串。Switch實作對String的操作,主要是對他做了一次hashCode(),而且hashCode()正好傳回的是int。
3. equals與==的差別。
(1)比較java基本類型:比較基本類型隻能用"==",不能用"equals",這裡的"=="比較的是兩個基本類型的值
(2)比較包裝類和String:"=="比較的是記憶體位址,"equals"比較的是值
"=="除了比較基本資料之外都是比較的記憶體位址
"equals"除了沒有沒有重寫equals方法的類之外都是比較的内容
4. Object有哪些公用方法?
equals()、getClass()、toString()、wait()、notify()、notifyAll()、hashCode()
5. Java的四種引用,強弱軟虛,用到的場景。
強引用:最常見的,不會被GC回收的對象,如 Object obj = new Object();
軟引用:可有可無的對象,如果記憶體空間足夠,GC就不會去回收這個對象,如果記憶體不足,就會回收,軟引用可有和ReferenceQueue(引用隊列)聯合使用,如果軟引用所引用的對象呗GC回收,JVM就會把這個軟引用加入到引用隊列中。
弱引用:也是描述可有可無的對象,和軟引用不同的是,它的生命周期更短,在GC的過程中,一旦發現有弱引用的對象,不管目前記憶體空間是否足夠,都會回收它的記憶體。真是因為這個特性,是以弱引用常用于Map資料結構中,引用占用空間記憶體較大的對象。
虛引用:也成幽靈引用,他的構造方法必須傳遞RefenceQueue參數,當GC準備回收一個對象時,發現它還有虛引用,就會在回收前,把虛引用加入到引用隊列中,程式可以通過判斷隊列中是否加入虛引用來判斷被引用的對象是否将要GC回收,進而可以在finalize方法中采取措施。
6. Hashcode的作用。
1)、hashCode的存在主要是用于查找的快捷性,如Hashtable,HashMap等,hashCode是用來在散列存儲結構中确定對象的存儲位址的;
2)、如果兩個對象相同,就是适用于equals(java.lang.Object) 方法,那麼這兩個對象的hashCode一定要相同;
3)、如果對象的equals方法被重寫,那麼對象的hashCode也盡量重寫,并且産生hashCode使用的對象,一定要和equals方法中使用的一緻,否則就會違反上面提到的第2點;
4)、兩個對象的hashCode相同,并不一定表示兩個對象就相同,也就是不一定适用于equals(java.lang.Object) 方法,隻能夠說明這兩個對象在散列存儲結構中,如Hashtable,他們“存放在同一個籃子裡”。
再歸納一下就是hashCode是用于查找使用的,而equals是用于比較兩個對象的是否相等的。
7. ArrayList、LinkedList、Vector的差別。
ArrayList和Vector都是基于數組的,ArrayList線程不安全(讀寫較快),vector線程安全。
LinkedList采用雙向連結清單實作,查詢稍慢,插入較快。
8. String、StringBuffer與StringBuilder的差別。
String 字元串常量
StringBuffer 字元串變量(線程安全)
StringBuilder 字元串變量(非線程安全)
9. Map、Set、List、Queue、Stack的特點與用法。
Map:以鍵值對形式存入資料,而且鍵可以是null值,但是隻能為一個null值,後面的null值會覆寫前面的。
Set:繼承Collection接口,放入資料沒有順序,像HashSet其實就是采用HashMap的key值來來存放Set的value;不能放入重複值,可以存入null值
List:繼承Collection接口,可以放入重複值,可以存入null值,放入的是有順序的
Stack:棧,先進後出,LinkedList也是可以實作棧,但是在java中并沒有讓LinkedList繼承Stack類,而是有一預設的Stack類。Java.util包中的棧繼承了Vector,是以Stack類是用數組實作的,而且是線程安全的。
Queue:隊列,先進後出,LinkedList及繼承了接口,是以可以用LinkedList建立queue;
10. HashMap和HashTable的差別。
HashMap是Hashtable的輕量級實作(非線程安全的實作),他們都完成了Map接口,主要差別在于HashMap允許空(null)鍵值(key),由于非線程安全,效率上可能高于Hashtable。 HashMap允許将null作為一個entry的key或者value,而Hashtable不允許。 HashMap把Hashtable的contains方法去掉了,改成containsvalue和containsKey。因為contains方法容易讓人引起誤解。 Hashtable繼承自Dictionary類,而HashMap是Java1.2引進的Map interface的一個實作。 最大的不同是,Hashtable的方法是Synchronize的,而HashMap不是,在多個線程通路Hashtable時,不需要自己為它的方法實作同步,而HashMap 就必須為之提供外同步。Hashtable直接使用對象hashCode,而HashMap重新計算hash值。Hashtable中hash數組預設大小11,增加方式old*2+1,而HashMap預設16,且一定是2的指數。
11. HashMap和ConcurrentHashMap的差別,HashMap的底層源碼。
HashMap标準鍊位址法實作
Collections.synchronizedMap(Map map);函數傳回的線程安全的HashMap
ConcurrentHashMap是一個經常被使用的資料結構,相比于Hashtable以及Collections.synchronizedMap()(給對象添加對象鎖),ConcurrentHashMap線上程安全的基礎上提供了更好的寫并發能力(多段鎖),但同時降低了對讀一緻性的要求。
在JDK1.5中,偉大的Doug Lea給我們帶來了concurrent包,從此Map也有安全的了。ConcurrentHashMap:在hashMap的基礎上,ConcurrentHashMap将資料分為多個segment,預設16個(concurrency level),然後每次操作對一個segment加鎖,避免多線程鎖的幾率,提高并發效率。JDK1.8後,ConcurrentHashMap進行了巨大改動。摒棄了Segment(鎖段)的概念,而是啟用了一種全新的方式實作,利用CAS(Compare and Swap)算法。它沿用了與它同時期的HashMap版本的思想,底層依然由“數組”+連結清單+紅黑樹的方式思想(JDK7與JDK8中HashMap的實作),但是為了做到并發,又增加了很多輔助的類,例如TreeBin,Traverser等對象内部類。詳見http://blog.csdn.net/qq407388356/article/details/79546165。
12. TreeMap、HashMap、LindedHashMap的差別。
HashMap就是标準鍊位址法實作
TreeMap基于紅黑樹(Red-Black tree)實作。該映射根據其鍵的自然順序進行排序,或者根據建立映射時提供的 Comparator 進行排序,具體取決于使用的構造方法。LinkedHashMap是HashMap的一個子類,它保留插入的順序。
13. Collection包結構,與Collections的差別。
Collection叫類集,包含了4個結構,List接口,Set接口,Queue接口,BeanContext接口。對于List接口的标準實作有abstractList類,Vector類,LinkedList類,ArrayList類(同時繼承abstractList),copyOnwriteArrayLIst類,對于Set的被一個AbstractSet實作,其他标準繼承abstractSet,實作由hashSet類,copyonwriteArraySet類,TreeSet類(跟hashSet類似,也是用TreeMap實作的),ConcurrentSkipArraySet;
使用類集的總用統一管理單列集合容器,對各個容器實作了标準化。易于我們擴充自己的類。
collections是集合類的一個幫助類(工具類),提供了一系列靜态方法對集合進行排序,搜尋線程安全等操作(Collections.sort(),Collections.Copy(),Colections。sysnchronizedList()Collections.sysnchronizedMap()等)
14. trycatch finally,try裡有return,finally還執行麼?
在執行try塊或者catch塊裡面的return之前,執行finally,如果finally裡有return,則直接return。
15. Excption與Error包結構。OOM你遇到過哪些情況,SOF你遇到過哪些情況。
Thorwable類所有異常和錯誤的超類,有兩個子類Error和Exception,分别表示錯誤和異常。
運作時異常(非檢查性異常):不處理可以通過編譯
非運作時異常(檢測性異常):不處理不能通過編譯
Error一般是程式無法處理的錯誤,如OutofMemoryError,StackOverFlowError,ThreadDeath錯誤等。這類一般java虛拟機直接選擇線程終止。
OOM(Out of Memory):除了程式計數器外,虛拟機記憶體的其他幾個運作時區域都有發生OOM異常的可能
SOF(Stack Over Flow):對于棧溢出情況,可以通過設定-Xss參數來控制每一線程棧的大小,當減小每個線程棧大小,同時在函數方法記憶體放比較大或者多的局部變量,就會發生棧溢出。當然sof隻放生在虛拟機棧和本地方法棧,不會發生在java堆和方法區中。
16. Java面向對象的三個特征與含義。
封裝、繼承、多态。
17. Override和Overload的含義去差別。
覆寫和重載。
18. Interface與abstract類的差別。
都不能執行個體化
1)抽象類中的方法可以有方法體,就是能實作方法的具體功能,但是接口中的方法不行。
2)抽象類中的成員變量可以是各種類型的,而接口中的成員變量隻能是 public static final 類型的。
3)接口中不能含有靜态代碼塊以及靜态方法(用 static 修飾的方法),而抽象類是可以有靜态代碼塊和靜态方法。
4)一個類隻能繼承一個抽象類,而一個類卻可以實作多個接口。
java 1.8開始支援接口中定義靜态方法、可以有default方法。
19. Staticclass 與non static class的差別。
在java中靜态類隻有靜态内部類這一種定義,其他的都是非靜态類。
java中靜态内部類和非靜态内部類的差別:靜态内部類相當于外部類的一個靜态屬性,是以他不能使用外部類的非靜态屬性和非靜态方法。而非靜态内部類相當于外部類非靜态屬性,是以可以使用靜态字段和非靜态字段或者方法。
靜态内部類存在的價值在于:靜态内部類可以建立靜态屬性,而非靜态内部類不可以建立靜态屬性。(内部類隻有在需要的時候才會加載),在這裡在每個類中用靜态main()方法做測試就派上用場了啊。
20. java多态的實作原理。
重載多态,編譯階段,靜态分派,方法參數來确定重載的方法。
重寫多态,父類引用指向子類,(動态分派)動态綁定。
21. 實作多線程的兩種方法:Thread與Runable。
繼承Thread類或Runable接口,都重寫run()方法。
還可以通過Callable接口和Future接口實作多線程。詳見http://blog.csdn.net/qq407388356/article/details/78535703。
22. 線程同步的方法:sychronized、lock、reentrantLock等。
synchronized關鍵字是jvm虛拟機的關鍵字,在java.util.concurrent.locks命名空間中還有一個Lock接口,和Lock接口的實作類ReentrantLock(可重入鎖)。 ReentrantLock可以實作和synchronized關鍵字相同的功能,而且更為靈活,在極端的情況下性能會更好一些。
23. 鎖的等級:方法鎖、對象鎖、類鎖。
synchronized
對象鎖,在修飾代碼塊的時候需要一個reference對象作為鎖的對象.
方法鎖,在修飾方法的時候預設是目前對象作為鎖的對象.
類鎖,synchronized修飾靜态的方法或代碼塊
同時介紹一下下面幾種鎖:
1:可重入鎖:隻得是如果一個線程擷取了一個對象鎖以後,如果該線程擷取該對象鎖鎖定的方法塊,則會直接進入,而不用重新申請鎖;Lock和syschronized都是可重入鎖。(可重入就設計到進入一次,計數器+1,沒出來一次,計數器-1)
2:可中斷鎖:如果某一線程A正在執行鎖中的代碼,另一線程B正在等待擷取該鎖,可能由于等待時間過長,線程B不想等待了,想先處理其他事情,我們可以讓它中斷自己或者在别的線程中中斷它,這種就是可中斷鎖。Lock就是可中斷鎖,而sysnchronized是不可中斷的。
3:公平鎖:公平鎖即盡量以請求鎖的順序來擷取鎖。比如同是有多個線程在等待一個鎖,當這個鎖被釋放時,等待時間最久的線程(最先請求的線程)會獲得該所,這種就是公平鎖。非公平鎖則可能是随機的或按照其他優先級,有的線程可能永遠也不能獲得該鎖。synchronized就是非公平鎖,ReentrantLock和ReentrantReadWriteLock,它預設情況下是非公平鎖,但是可以設定為公平鎖。
4:讀寫鎖:讀寫鎖将對一個資源(比如檔案)的通路分成了2個鎖,一個讀鎖和一個寫鎖。ReadWriteLock就是讀寫鎖,它是一個接口,ReentrantReadWriteLock實作了這個接口。
24. 寫出生産者消費者模式。
生産者和消費者之間進行同步操作。用synchronized關鍵字和wait()/notifyAll()實作或用ReentrantLock鎖和Condition變量來實作。
25. ThreadLocal的設計理念與作用。
提供線程内部的局部變量,在本線程内随時随地可取,隔離其他線程。TheadLocal的建立方式ThreadLocal<Integer> local = new ThreadLocal<Integer>();
ThreadLocal中有一個靜态内部類ThreadLocalMap(該map就了解為hashMap吧,隻是改map中的enty實體繼承了弱引用,也就是說,如果該Map中的對象太多的時候,即使我們沒有主動放棄,可能垃圾回收器回收);同時在Thread類中有一ThreadLocalMap的組合,為ThreadLocal.ThreadLocalMap<ThreadLocal,Object>threadLocals;從這裡可以看出,當在一個線程中調用local.set(100)方法的時候,則在該線程對象的ThreadLocalMap中存入<local,100>;當通過local.get()方法的時候,則先擷取目前線程,通過目前線程擷取ThreadLocalMap,然後,通過該local變量為key值去擷取對應的value(100);
TheadLocal變量不是用來實作資源共享的,而是用來實作資源的在各個線程中的隔離。各個線程單獨占有。雖然也可用局部變量,但是有些場景,如果說資源隻有一個的時候,就得使用ThreadLcoal變量。還有要注意是對一個對象,如ThreadLocal<Person>這種狀況,則map中存的是指向person的引用。要特别小心。
26. ThreadPool用法與優勢。
第一:降低資源消耗。通過重複利用已建立的線程降低線程建立和銷毀造成的消耗。第二:提高響應速度。當任務到達時,任務可以不需要等到線程建立就能立即執行。第三:提高線程的可管理性。線程是稀缺資源,如果無限制的建立,不僅會消耗系統資源,還會降低系統的穩定性,使用線程池可以進行統一的配置設定,調優和監控。但是要做到合理的利用線程池,必須對其原理了如指掌。用法詳見http://blog.csdn.net/qq407388356/article/details/79551451。
27. Concurrent包裡的其他東西:ArrayBlockingQueue、CountDownLatch等等。
l BlockingQueue
如果BlockingQueue是空的,從BlockingQueue取東西的操作将會被阻斷進入等待狀态,直到BlockingQueue進了東西才會被喚醒,同樣,如果BlockingQueue是滿的,任何試圖往裡存東西的操作也會被阻斷進入等待狀态,直到BlockingQueue裡有空間時才會被喚醒繼續操作。 BlockingQueue有四個具體的實作類,
ArrayBlockingQueue:規定大小的BlockingQueue,其構造函數必須帶一個int參數來指明其大小。其所含的對象是以FIFO(先入先出)順序排序的。
LinkedBlockingQueue:大小不定的BlockingQueue,若其構造函數帶一個規定大小的參數,生成的BlockingQueue有大小限制,若不帶大小參數,所生成的BlockingQueue的大小由Integer.MAX_VALUE來決定。其所含的對象是以FIFO順序排序的。
PriorityBlockingQueue:類似于LinkedBlockingQueue,但其所含對象的排序不是FIFO,而是依據對象的自然排序順序或者是構造函數所帶的Comparator決定的順序。
SynchronousQueue:特殊的BlockingQueue,對其的操作必須是放和取交替完成的。
l Semaphore
Java 并發庫的Semaphore 可以很輕松完成信号量控制,Semaphore可以控制某個資源可被同時通路的個數,acquire()擷取一個許可,如果沒有就等待,而release()釋放一個許可。比如在Windows下可以設定共享檔案的最大用戶端通路個數。
l CountdownLatch
CountDownLatch的一個非常典型的應用場景是:有一個任務想要往下執行,但必須要等到其他的任務執行完畢後才可以繼續往下執行。假如我們這個想要繼續往下執行的任務調用一個CountDownLatch對象的await()方法,其他的任務執行完自己的任務後調用同一個CountDownLatch對象上的countDown()方法,這個調用await()方法的任務将一直阻塞等待,直到這個CountDownLatch對象的計數值減到0為止。(當每個線程調用countdown方法直到将countdownlatch方法建立時數減為0時,那麼之前調用await()方法的線程才會繼續執行。有一點注意,那就是隻執行一次,不能到0以後重新執行)
l CyclicBarrier
類有一個整數初始值,此值表示将在同一點同步的線程數量。當其中一個線程到達确定點,它會調用await() 方法來等待其他線程。當線程調用這個方法,CyclicBarrier阻塞線程進入休眠直到其他線程到達。當最後一個線程調用CyclicBarrier 類的await() 方法,它喚醒所有等待的線程并繼續執行它們的任務。(當等待的線程數量達到CyclicBarrier線程指定的數量以後(調用await方法的線程數),才一起往下執行,否則大家都在等待,注意:如果達到指定的線程數量的時候:則可以重新計數,上面的過程可以循環)
CountDownLatch是減計數方式,計數==0時釋放所有等待的線程;CyclicBarrier是加計數方式,計數達到構造方法中參數指定的值時釋放所有等待的線程。
28. wait()和sleep()的差別。
調用sleep()和yield()時鎖沒有釋放,但是在sleep的時候,可以調用interrupt()函數來中斷該線程。調用wait()時,線程被挂起釋放鎖。
wait()是Object類中,與notify和notifyAll搭配使用,sleep()屬于Thread類中的。
suspend将目前線程挂起,要等到線程調用resume()方法,該線程才能重新執行。
29. foreach與正常for循環效率對比。
直接for循環效率最高,其次是疊代器和 ForEach操作。其實 ForEach 編譯成位元組碼之後,使用的是疊代器實作的。比疊代器周遊多了生成中間變量這一步,因為性能也略微下降了一些。
在多線程中,則使用foreach,如果是在方法中讀局部變量的操作,則使用for。
30. Java IO與NIO。
IO是面向流的,NIO是面向緩沖區的
IO的各種流是阻塞的,Java NIO的非阻塞模式
Java NIO的選擇器允許一個單獨的線程來監視多個輸入通道
31. 反射的作用與原理。
動态加載類,在運作時load到記憶體中。反射機制的原理:反射就是java語言在運作時可以通過擷取類的class對象,并通過class對象擷取到目前對象的方法(包括私有方法),屬性,以及構造方法,運作時class對象相當于外部程式通路記憶體中該類的一道門,通過該到門能擷取到運作時該類的各種東西。
Spring中的IoC的實作原理就是工廠模式加反射機制。
32. 泛型常用特點,List<String>能否轉為List<Object>。
泛型的好處是在編譯的時候檢查類型安全(類型檢查是保證類型轉換是可以正确轉換的(object編譯的時候就沒有檢查到父類轉子類)),并且所有的強制轉換都是自動和隐式的,提高代碼的重用率。編譯之後都會擦除。List<String>不能轉為List<Object>,因為泛型并不具有繼承性。隻是一個限定的作用。
33. 解析XML的幾種方式的原理與特點:DOM、SAX、PULL。
1:DOM是基于樹的解析,DOM是把XML全部加載到記憶體中建立一棵樹之後再進行處理。是以DOM不适合處理大型的XML【會産生記憶體的急劇膨脹】。這樣可以随時修改xml檔案内容。
2:SAX基于事件的解析,sax解析一行一行的讀取xml檔案開始标記的時候執行startElement方法,然後執行對應解析方法character方法,當遇到結束表示符就調用endElement方法,是以所是基于事件型解析, SAX不必把全部的xml都加載到記憶體中。但是SAX的缺點也很明顯,它隻能對檔案順序解析一遍,不支援對檔案的随意存取。SAX也僅僅能夠讀取檔案的内容,并不能修改内容。DOM可以随意修改檔案樹。(主要用于讀取xml檔案)
3:SAX 和 DOM 不是互相排斥的,記住這點很重要。可以使用 DOM 來建立 SAX 事件流,也可以使用 SAX 來建立 DOM 樹。事實上,用于建立 DOM 樹的大多數解析器實際上都使用 SAX 來完成。
34. Java與C++對比。
(1)Java比C++程式可靠性更高。
(2)Java語言中沒有指針的概念,
(3)Java用接口(Interface)技術取代C++程式中的多繼承性;
(4)Java語言不需要程式對記憶體進行配置設定和回收。Java中自動回收記憶體,而c++中要調用new和delete來申請和釋放記憶體,如果對記憶體配置設定與申請掌握不好就容易報錯
(5)異常:JAVA中的異常機制用于捕獲例外事件,增強系統容錯能力 try{//可能産生例外的代碼 }catch(exceptionTypename){ //處理 } 其中exceptionType表示異常類型。而C++則沒有如此友善的機制
(6)Java不提供goto語句,指定goto作為關鍵字,但不支援它的使用,使程式簡潔易讀。
35. Java1.7與1.8新特性。
1.7新特性:
1:switch中可以使用字串了運用
2:List<String> tempList = new ArrayList<>(); 即泛型執行個體化類型自動推斷
3.文法上支援集合,而不一定是數組final List<Integer> piDigits = [ 1,2,3,4,5,8 ];
4:try塊可以不用finally手動關閉,直接try塊中就可以關閉Try-With-Resource文法
5:很長的數字可讀性不好,在Java 7中可以使用下劃線分隔長int以及long了,如1_1 * 10 = 110,120 – 1_0 = 110
Java1.8新特性
1: Java 8允許我們給接口添加一個非抽象的方法實作,隻需要使用 default關鍵字即可,default double sqrt(int a) {return Math.sqrt(a);},改方法不用實作,可以自己直接通過子類調用。
2:增加了lamda表達式
3:Java 8 在包java.time下包含了一組全新的時間日期API
36. JNI的使用。
1:JNI(Java Native Interface)就是通過java本地方法可以調用其他語言的代碼,能與其它語言(如C、C++)的動态庫進行互動
2:JNI的使用場景
java是一門半解釋性的語言,代碼很容易被别人反編譯,是以可以采用jni通過c語言或者c++來實作其核心,這樣還能提高一定的性能;
一些性能要求特别高時,可以采用彙編語言實作,通過jni調用;
别的語言已經實作了的功能,通過jni可以直接調用,而不用重新編寫。
jni使用步驟:用native關鍵字定義本地方法,然後編譯該類為class檔案,用javah工具生成.h的頭檔案,然後用c/c++語言實作其中的.h頭檔案中的方法,并生成動态庫(以.so結尾的檔案,大多數動态庫是以.dll檔案結尾的)),然後提供給java使用
37. Java是否有記憶體洩露和記憶體溢出
靜态集合類:由于他們的生命周期和應用程式一樣長,不斷添加對象時,可能會造成記憶體洩露。
監聽器:增加監聽器時,往往釋放的時候沒有删除對應的監聽器。
實體連接配接:資料庫和網絡連接配接等,除非顯示關閉了連接配接,否則不會被GC自動回收。當不用時必須用close()來釋放,因為這些連接配接獨立于JVM。一般在try塊中建立連接配接,在finally裡釋放。
還有内部類和單例模式等,其實總結起來就是JVM對象是否可達{虛拟機棧(棧幀中的本地變量表)中引用的對象;方法區中類靜态屬性引用的對象;方法區中常量引用的對象;本地方法棧中JNI(Native方法)引用的對象}。
38. Student s= new Student();在記憶體中做了哪些事
加載Student.class檔案;在棧内為s開辟空間;在堆内為student對象開辟空間;對student成員變量進行預設初始化;對student成員變量進行顯示初始化;通過構造方法對student對象成員變量指派;student初始化完畢把對象引用指派給s。
39. 持續更新。。。
有新的問題會繼續更新。。。