1. 程式人生 > >面試通關要點彙總集一

面試通關要點彙總集一

基礎篇

面向物件的特徵

1、封裝:封裝隱藏了類的內部機制,可以在不影響使用的情況下改版類的內部結構,同時也保護了資料。對外界而言它的內部細節是隱藏的,暴露給外界的只是它的訪問方法。

2、繼承:繼承給物件提供了從基類獲取欄位和方法的能力。繼承提供了程式碼的重用行,也可以在不修改類的情況下給現存的類新增新特性

3、多型:多型首先是建立在繼承的基礎上,指不同的子類在繼承父類後分別都重寫覆蓋了父類的方法,即父類同一個方法,在繼承的子類中表現出不同的形式。

4、抽象:抽象是把想法從具體的例項中分離出來的步驟,因此,要根據他們的功能而不是實現細節來建立類。 Java 支援建立只暴漏介面而不包含方法實現的抽象的類。這種抽象技術的主要目的是把類的行為和實現細節分離開

final, finally, finalize 的區別

final:修飾符(關鍵字)如果一個類被宣告為final,意味著它不能再派生出新的子類,不能作為父類被繼承。因此一個類不能既被宣告為 abstract的,又被宣告為final的。將變數或方法宣告為final,可以保證它們在使用中不被改變。被宣告為final的變數必須在宣告時給定初值,而在以後的引用中只能讀取,不可修改。被宣告為final的方法也同樣只能使用,不能過載。

finally:是異常處理語句結構的一部分,表示總是執行。

finalize:是Object類的一個方法,在垃圾收集器執行的時候會呼叫被回收物件的次方法,供垃圾收集時的其他資源回收,例如關閉檔案等。

 

int 和 Integer 有什麼區別

1、無論如何,Integer和new Integer不會相等,不會經歷拆箱過程,new出來的物件存放在堆,而非new的Integer常量則在常量池(方法區),他們的記憶體地址不一樣,所以為false。

2、兩個都是非new出來的Integer,如果數在-128到127之間,則時true,否則為false。因為java在編譯Integer i2 =128的時候,被翻譯成:Integer i2 = Integer.valueOf(128);而valueOf()函式會對-128到127之間的數進行快取。

3、兩個都是new出來的,都是false,還是記憶體地址不一樣。

4、int和Integer(無論new否)比,都為true,因為會把Integer自動拆箱為int再去比

 

過載和重寫的區別

重寫:子類中對父類的方法進行重新定義,其子類的方法名以及引數位置和個數均與父類相同,從而在呼叫子類的該方法時,不會執行父類的方法。簡單來說就是方法同名同參

過載:就是在類中可以建立多個方法,它們具有相同的名字,但具有不同的引數和不同的定義。呼叫時通過引數型別和個數來決定呼叫那個方法。簡單來說就是方法同名不同參

 

抽象類和介面有什麼區別

1、抽象類和介面都不能例項化

2、抽象類要被子類繼承,介面要被類實現

3、介面只能做方法申明,抽象類中可以做方法申明,也可以做方法實現

4、接口裡定義的變數只能是公告共的靜態的常量,抽象類中的變數是普通變數

5、抽象類裡的抽象方法必須全部被子類所實現,如果子類不能全部實現父類的抽象方法,那麼該子類只能是抽象類,同樣,一個實現介面的時候,如不能全部實現介面的方法,那麼該類也只能為抽象類

6、抽象方法只能申明,不能實現,介面是設計結果,抽象類是重構的結果

7、 抽象類裡可以沒有抽象方法

8、如果一個類裡有抽象方法,那麼這個類只能是抽象類

9、抽象方法要被實現,所以不能是靜態的,也不能是私有的

10、介面可繼承介面,並可多繼承介面,但類只能是單繼承

 

說說反射的用途及實現

反射的核心是JVM在執行時才動態載入類或呼叫方法/訪問屬性,它不需要事先(寫程式碼的時候或編譯器)知道執行物件是誰。

一、Java反射框架主要提供一下功能:

1、在執行時判斷任意一個物件所屬的類

2、在執行時構造任意一個物件

3、在執行時判斷任意一個類所具有的成員變數和方法(通過反射甚至可以呼叫private方法)

4、在執行時呼叫任意一個物件的方法

二、反射的應用很多,很多框架都有用到

spring 的 ioc/di 也是反射…
javaBean和jsp之間呼叫也是反射…
struts的 FormBean 和頁面之間…也是通過反射呼叫…
JDBC 的 classForName()也是反射…
hibernate的 find(Class clazz) 也是反射…

反射還有一個不得不說的問題,就是效能問題,大量使用反射系統性能大打折扣。怎麼使用使你的系統達到最優就看你係統架構和綜合使用問題啦,這裡就不多說了

三、基本反射功能的實現(反射相關的類一般都在java.lang.relfect包裡):

1、獲得Class物件

      使用Class類的forName靜態方法

      直接獲取某一個物件的class

      呼叫某個物件的getClass()方法

2、判斷是否為某個類的例項

      用instanceof關鍵字來判斷是否為某個類的例項

3、建立例項

      使用Class物件的newInstance()方法來建立Class物件對應類的例項。

      先通過Class物件獲取指定的Constructor物件,再呼叫Constructor物件的newInstance()方法來建立例項。

4、獲取方法

      getDeclaredMethods()

5、獲取構造器資訊

      getDeclaredMethods()

      getMethods()

      getMethod()

6、獲取類的成員變數(欄位)資訊

      getFiled: 訪問公有的成員變數
      getDeclaredField:所有已宣告的成員變數。但不能得到其父類的成員變數
      getFileds和getDeclaredFields用法

7、呼叫方法

       invoke()

8、利用反射建立陣列

       Array.newInstance()

 

HTTP 請求的 GET 與 POST 方式的區別

1、GET方法會把引數附加在請求的URL後面,因為URL對字元數目有限制,進而限制了使用者在客戶端請求的引數值的數目,並且請求中的引數值是可見的,因此,敏感資訊不能用這種方式傳遞。

2、POST方法通過把請求引數值放到請求體中來客服GET方法的限制,因此,可以傳送的引數的數目是沒有限制的。最後,通過POST請求傳遞的敏感資訊對外部客戶端是不見的。

 

session 與 cookie 區別

1、cookie是儲存在客戶端的,伺服器可以知道其中的資訊。session是儲存在伺服器的,客戶端不知道其中的資訊。

2、session中儲存的是物件,cookie中儲存的是字串

3、session不能區分路徑,同一個使用者在訪問一個網站期間,所有的session在任何一個地方都可以訪問到;而cookie中如果設定了路徑引數,那麼同一個網站中不同路徑下的cookie互相是飯問不到的

 

session 分散式處理幾種方式:

1、session黏性:就是說使用者訪問了某臺機器後,之後的操作就讓其只走該臺伺服器就好。eg:nginx配置

upstream test{
    #這裡新增的是上面啟動好的兩臺伺服器
    ip_hash;#粘性Session
     server 192.168.22.229:8080 weight=1;
     server 192.168.22.230:8080 weight=1;
}

優點:操作簡單,不對session做任何操作

缺點:當一臺機器掛掉後,流量切向其它機器。會丟失部分使用者的session

使用場景:傳送故障對客戶產生的影響小;伺服器傳送故障是低概率事件

2、使用廣播的方式

當一臺伺服器中的session中(增刪改)了之後,將這個session中的所有資料,通過廣播一樣的方式,同步到其他的伺服器中去

優點:容錯性增高 

缺點:機器不能太多,session數量不能太大,否則會造成網路阻塞,是伺服器變慢

3、使用中介軟體共享session

將使用者的session存放在redis上,使用者在訪問的時候,讀取修改都在redis上目前這種做法是大家使用最多的方法

 

JDBC 流程

1、載入JDBC驅動:在連線資料庫之前,首先要載入想要連線的資料庫的驅動到JVM(Java虛擬機器),成功載入後,會將Driver類的例項註冊到DriverManager類中。

Class.forName("com.mysql.jdbc.Driver") ;

2、建立資料庫的連線:要連線資料庫,需要向java.sql.DriverManager請求並獲得Connection物件, 該物件就代表一個數據庫的連線

Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "root") ;

3、建立一個Statement:要執行SQL語句,必須獲得java.sql.Statement例項,Statement例項分為以下3 種類型:

4、執行SQL語句

5、處理結果

6、關閉JDBC物件

 

MVC 設計思想

       是一種軟體架構的思想,將一個軟體按照模型、檢視、控制器進行劃分。其中,模型用來封裝業務邏輯,檢視用來實現表示邏輯,控制器用來協調模型與檢視(檢視要通過控制器來呼叫模型,模型返回的處理結果也要先交給控制器,由控制器來選擇合適的檢視來顯示 處理結果)。

1)模型(M): 業務邏輯包含了業務資料的加工與處理以及相應的基礎服務(為了保證業務邏輯能夠正常進行的事務、安全、許可權、日誌等等的功能模組)
 2)檢視(v):展現模型處理的結果;另外,還要提供相應的操作介面,方便使用者使用。
 3)控制器(c):檢視發請求給控制器,由控制器來選擇相應的模型來處理;模型返回的結果給控制器,由控制器選擇合適的檢視。
 

equals 與 == 的區別

簡單來說:equals比較兩個物件的內容是否相同,== 比較兩個物件是否是同一物件

1、對於基本資料型別而言(byte、short、char、int、long、float、double、boolean),它們之間的比較應該用“==”,比較的是它們的值

2、對於複合(引用)資料型別而言,如果使用“==”進行比較,則比較的是它們的引用是否相同,即它們的記憶體地址是否是同一個,因此,只有是同一個“new”出來的物件,比較的結果才為true,否則都為false

3、對於Object類中的"equals()"方法,預設的比較是和“==”的作用是一樣的,即當"equals()"方法沒有被重寫(原生的“equals()”方法)的時候,比較的同樣是兩者的記憶體地址是否是同一個。但是!但是!但是:(重要的事情講3遍)如果"equals()"方法被一些類(例如:String、Date、Integer...)重寫了,則比較的是它們的內容是否相同

 

集合

List 和 Set 區別

List,Set都是繼承自Collection介面

List特點:元素有放入順序,元素可重複

Set特點:元素無放入順序,元素不可重複,重複元素會覆蓋掉

(注意:元素雖然無放入順序,但是元素在set中的位置是有該元素的HashCode決定的,其位置其實是固定的,加入Set 的Object必須定義equals()方法 ,另外list支援for迴圈,也就是通過下標來遍歷,也可以用迭代器,但是set只能用迭代,因為他無序,無法用下標來取得想要的值。)

Set和List對比:

Set:檢索元素效率低下,刪除和插入效率高,插入和刪除不會引起元素位置改變。

List:和陣列類似,List可以動態增長,查詢元素效率高,插入刪除元素效率低,因為會引起其他元素位置改變。
 

List 和 Map 區別

List是物件集合,允許物件重複。

Map是鍵值對的集合,不允許key重複

 

Arraylist 與 LinkedList 區別

Arraylist:查詢塊,增刪慢

優點:ArrayList是實現了基於動態陣列的資料結構,因為地址連續,一旦資料儲存好了,查詢操作效率會比較高(在記憶體裡是連著放的)。

缺點:因為地址連續, ArrayList要移動資料,所以插入和刪除操作效率比較低。

LinkedList:查詢慢,增刪快

優點:LinkedList基於連結串列的資料結構,地址是任意的,所以在開闢記憶體空間的時候不需要等一個連續的地址,對於新增和刪除操作add和remove,LinedList比較佔優勢。LinkedList 適用於要頭尾操作或插入指定位置的場景

缺點:因為LinkedList要移動指標,所以查詢操作效能比較低。

適用場景分析:

當需要對資料進行對此訪問的情況下選用ArrayList,當需要對資料進行多次增加刪除修改時採用LinkedList。

 

ArrayList 與 Vector 區別

ArrayList和Vector都是用陣列實現的,主要有這麼三個區別:

Vector是多執行緒安全的,執行緒安全就是說多執行緒訪問同一程式碼,不會產生不確定的結果。而ArrayList不是,這個可以從原始碼中看出,Vector類中的方法很多有synchronized進行修飾,這樣就導致了Vector在效率上無法與ArrayList相比;

兩個都是採用的線性連續空間儲存元素,但是當空間不足的時候,兩個類的增加方式是不同。

Vector可以設定增長因子,而ArrayList不可以。

Vector是一種老的動態陣列,是執行緒同步的,效率很低,一般不贊成使用。

 

HashMap 和 Hashtable 的區別

1.hashMap去掉了HashTable 的contains方法,但是加上了containsValue()和containsKey()方法。

2.hashTable同步的,而HashMap是非同步的,效率上比hashTable要高。

3.hashMap允許空鍵值,而hashTable不允許。
 

HashSet 和 HashMap 區別

set是線性結構,set中的值不能重複,hashset是set的hash實現,hashset中值不能重複是用hashmap的key來實現的。

map是鍵值對對映,可以空鍵空值。HashMap是Map介面的hash實現,key的唯一性是通過key值hash值的唯一來確定,value值是則是連結串列結構。

他們的共同點都是hash演算法實現的唯一性,他們都不能持有基本型別,只能持有物件
 

HashMap 和 ConcurrentHashMap 的區別

ConcurrentHashMap是執行緒安全的HashMap的實現。

(1)ConcurrentHashMap對整個桶陣列進行了分割分段(Segment),然後在每一個分段上都用lock鎖進行保護,相對於HashTable的syn關鍵字鎖的粒度更精細了一些,併發效能更好,而HashMap沒有鎖機制,不是執行緒安全的。

(2)HashMap的鍵值對允許有null,但是ConCurrentHashMap都不允許。
 

HashMap 的工作原理及程式碼實現

參考:https://blog.csdn.net/qq_26857649/article/details/81713311

 

ConcurrentHashMap 的工作原理及程式碼實現

參考:https://blog.csdn.net/qq_26857649/article/details/81712894

 

執行緒

建立執行緒的方式及實現

Java中建立執行緒主要有三種方式:

1、繼承Thread類建立執行緒類

public class MyThread extends Thread{//繼承Thread類

  public void run(){//重寫run方法}

}

public class Main {

  public static void main(String[] args){

    new MyThread().start();//建立並啟動執行緒

  }

}

2、通過Runnable介面建立執行緒類

public class MyThread2 implements Runnable {//實現Runnable介面

  public void run(){}

}

public class Main {

  public static void main(String[] args){

    new Thread(new MyThread2()).start();

  }

}

3、通過Callable和Future建立執行緒

 

sleep(),wait(),yield()和join()方法的區別

sleep() :讓當前正在執行的執行緒暫停一段時間,進入阻塞狀態,但不會釋放鎖。

wait() :wait()方法與sleep()方法的不同之處在於,wait()方法會釋放物件的“鎖標誌”,當呼叫某一物件的wait()方法後,會使當前執行緒暫停執行,並將當前執行緒放入物件等待池中,直到呼叫了notify()方法後,將從物件等待池中移出任意一個執行緒並放入鎖標誌等待池中,只有鎖標誌等待池中的執行緒可以獲取鎖標誌,它們隨時準備爭奪鎖的擁有權。當呼叫了某個物件的notifyAll()方法,會將物件等待池中的所有執行緒都移動到該物件的鎖標誌等待池。除了使用notify()和notifyAll()方法,還可以使用帶毫秒引數的wait(long timeout)方法,效果是在延遲timeout毫秒後,被暫停的執行緒將被恢復到鎖標誌等待池。 

yield() :yield()方法和sleep()方法類似,也不會釋放“鎖標誌”,區別在於,它沒有引數,即yield()方法只是使當前執行緒重新回到可執行狀態,所以執行yield()的執行緒有可能在進入到可執行狀態後馬上又被執行,另外yield()方法只能使同優先順序或者高優先順序的執行緒得到執行機會,這也和sleep()方法不同。

join() :join()方法會使當前執行緒等待呼叫join()方法的執行緒結束後才能繼續執行

 

說說 CountDownLatch 原理

分析CountDownLatch的實現原理

什麼時候使用CountDownLatch

Java併發程式設計:CountDownLatch、CyclicBarrier和Semaphore

 

說說 CyclicBarrier 原理

參考:

JUC回顧之-CyclicBarrier底層實現和原理

 

說說 Semaphore 原理

JAVA多執行緒–訊號量(Semaphore)

JUC回顧之-Semaphore底層實現和原理

 

說說 Exchanger 原理

java.util.concurrent.Exchanger應用範例與原理淺析

 

說說 CountDownLatch 與 CyclicBarrier 區別

儘量把CyclicBarrier和CountDownLatch的區別說通俗點

 

ThreadLocal 原理分析

Java併發程式設計:深入剖析ThreadLocal

 

講講執行緒池的實現原理、執行緒池的幾種方式

Java併發程式設計:執行緒池的使用

 

執行緒的生命週期

新建(New)、就緒(Runnable)、執行(Running)、阻塞(Blocked)和死亡(Dead)5種狀態

(1)生命週期的五種狀態

新建(new Thread)
當建立Thread類的一個例項(物件)時,此執行緒進入新建狀態(未被啟動)。
例如:Thread t1=new Thread();

就緒(runnable)
執行緒已經被啟動,正在等待被分配給CPU時間片,也就是說此時執行緒正在就緒佇列中排隊等候得到CPU資源。例如:t1.start();

執行(running)
執行緒獲得CPU資源正在執行任務(run()方法),此時除非此執行緒自動放棄CPU資源或者有優先順序更高的執行緒進入,執行緒將一直執行到結束。

死亡(dead)
當執行緒執行完畢或被其它執行緒殺死,執行緒就進入死亡狀態,這時執行緒不可能再進入就緒狀態等待執行。

自然終止:正常執行run()方法後終止

異常終止:呼叫**stop()**方法讓一個執行緒終止執行

堵塞(blocked)
由於某種原因導致正在執行的執行緒讓出CPU並暫停自己的執行,即進入堵塞狀態。

正在睡眠:用sleep(long t) 方法可使執行緒進入睡眠方式。一個睡眠著的執行緒在指定的時間過去可進入就緒狀態。

正在等待:呼叫wait()方法。(呼叫motify()方法回到就緒狀態)

被另一個執行緒所阻塞:呼叫suspend()方法。(呼叫resume()方法恢復)

 

鎖機制

說說執行緒安全問題

執行緒安全是指控制多個執行緒對某個資源的有序訪問或修改,而在這些執行緒之間沒有產生衝突。

 

volatile 實現原理

參考:https://blog.csdn.net/qq_26857649/article/details/81712849

 

synchronize 實現原理

參考:https://blog.csdn.net/qq_26857649/article/details/81713120

 

synchronized 與 lock 的區別

類別 synchronized Lock
存在層次 Java的關鍵字,在jvm層面上 是一個類
鎖的釋放 1、以獲取鎖的執行緒執行完同步程式碼,釋放鎖 2、執行緒執行發生異常,jvm會讓執行緒釋放鎖 在finally中必須釋放鎖,不然容易造成執行緒死鎖
鎖的獲取 假設A執行緒獲得鎖,B執行緒等待。如果A執行緒阻塞,B執行緒會一直等待 分情況而定,Lock有多個鎖獲取的方式,具體下面會說道,大致就是可以嘗試獲得鎖,執行緒可以不用一直等待
鎖狀態 無法判斷 可以判斷
鎖型別 可重入 不可中斷 非公平 可重入 可判斷 可公平(兩者皆可)
效能 少量同步 大量同步

 

悲觀鎖 樂觀鎖

悲觀鎖:認為總會有人爭搶

樂觀鎖:基本沒人搶(使用於讀多寫少的場景)

比如資料庫方面:悲觀鎖就是for update(鎖定查詢的行),樂觀鎖就是version欄位(比較跟上一次的版本號,如果一樣則更新,如果失敗則需要重複讀-比較-寫的操作)。

JDK方面:悲觀鎖就是sync,樂觀鎖就是原子類(內部CAS實現)

 

CAS 樂觀鎖和ABA問題

參考:https://blog.csdn.net/qq_26857649/article/details/81560494

 

資料儲存

MySQL 索引使用的注意事項

參考:https://blog.csdn.net/qq_26857649/article/details/83107157

 

說說分庫與分表設計

參考:https://blog.csdn.net/qq_26857649/article/details/83107983

 

分庫與分錶帶來的分散式困境與應對之策

參考:https://blog.csdn.net/qq_26857649/article/details/83108916

 

說說 SQL 優化之道

參考:https://blog.csdn.net/qq_26857649/article/details/83109255

 

MySQL 遇到的死鎖問題

參考:https://blog.csdn.net/qq_26857649/article/details/83109936

 

儲存引擎的 InnoDB 與 MyISAM

參考:https://blog.csdn.net/qq_26857649/article/details/83110005

 

資料庫索引的原理

參考:http://blog.csdn.net/suifeng3051/article/details/52669644

 

聚集索引與非聚集索引的區別

參考:https://blog.csdn.net/qq_26857649/article/details/83110492

 

limit 20000 載入很慢怎麼解決

LIMIT n 等價於 LIMIT 0,n

此題總結一下就是讓limit走索引去查詢,例如:order by 索引欄位,或者limit前面根where條件走索引欄位等等。

 

聊聊 ElasticSearch 使用場景

在一般情況下,關係型資料庫的模糊查詢,都是通過 like 的方式進行查詢。其中,like “value%” 可以使用索引,但是對於 like “%value%” 這樣的方式,執行全表查詢,這在資料量小的表,不存在效能問題,但是對於海量資料,全表掃描是非常可怕的事情。ElasticSearch 作為一個建立在全文搜尋引擎 Apache Lucene 基礎上的實時的分散式搜尋和分析引擎,適用於處理實時搜尋應用場景。此外,使用 ElasticSearch 全文搜尋引擎,還可以支援多詞條查詢、匹配度與權重、自動聯想、拼寫糾錯等高階功能。因此,可以使用 ElasticSearch 作為關係型資料庫全文搜尋的功能補充,將要進行全文搜尋的資料快取一份到 ElasticSearch 上,達到處理複雜的業務與提高查詢速度的目的。

 

快取使用

Redis 有哪些型別

Redis支援5種資料型別:String(字串)、hash(雜湊)、list(列表)、set(集合)、zset(有序集合)

 

聊聊 Redis 使用場景

隨著資料量的增長,MySQL 已經滿足不了大型網際網路類應用的需求。因此,Redis 基於記憶體儲存資料,可以極大的提高查詢效能,對產品在架構上很好的補充。例如,為了提高服務端介面的訪問速度,儘可能將讀頻率高的熱點資料存放在 Redis 中。這個是非常典型的以空間換時間的策略,使用更多的記憶體換取 CPU 資源,通過增加系統的記憶體消耗,來加快程式的執行速度。

在某些場景下,可以充分的利用 Redis 的特性,大大提高效率。這些場景包括快取,會話快取,時效性,訪問頻率,計數器,社交列表,記錄使用者判定資訊,交集、並集和差集,熱門列表與排行榜,最新動態等。

使用 Redis 做快取的時候,需要考慮資料不一致與髒讀、快取更新機制、快取可用性、快取服務降級、快取穿透、快取預熱等快取使用問題
 

Redis 持久化(RDB和AOF

參考:https://blog.csdn.net/qq_26857649/article/details/83111517

 

快取奔潰

Redis是一個開源的高效能鍵值儲存資料庫。之所以效能優異,是因為Redis是把所有的資料都存在記憶體中的。這樣會有一個問題:當伺服器重啟或程式異常崩潰時,Redis的資料就會全部丟失。雖然生產環境中,Redis僅被用於快取,但是如果能夠對其資料做持久化的操作,還是一個不錯的選擇。

Redis預設支援兩種持久話的方式,分別是基於快照形成的RDB檔案和基於命令操作儲存的AOF檔案

 

快取降級

服務降級的目的,是為了防止Redis服務故障,導致資料庫跟著一起發生雪崩問題。因此,對於不重要的快取資料,可以採取服務降級策略,例如一個比較常見的做法就是,Redis出現問題,不去資料庫查詢,而是直接返回預設值給使用者

 

框架篇

BeanFactory 和 ApplicationContext 有什麼區別

Beanfactory:顧名思義,它的核心概念就是bean工廠,用作於bean生命週期的管理。

Applicationcontext:包含的範圍更廣,它繼承自beanfactory但不僅僅是繼承自這一個介面,還有繼承了其他的介面,所以它不僅僅有bean factory相關概念,更是一個應用系統的上下文,其設計初衷應該是一個包羅永珍的對外暴露的一個綜合的API。

 

Spring Bean 的生命週期

參考:https://blog.csdn.net/qq_26857649/article/details/83154076

è¿éåå¾çæè¿°

 

說說 Spring AOP