java3年面試題

整理一下最近面試遇到過的問題,有一些想不起來了,希望能給大家一點幫助吧,也給自己留個底,嘿嘿,平時還是得多注意知識的積累,以及技術細節

- 1.JAVA基礎類型各佔幾個字節?

int 32bit
short 16bit
long 64bit
byte 8bit
char 16bit
float 32bit
double 64bit
boolean 1bit
boolean類型沒有給出精確的定義,《Java虛擬機規範》給出了4個字節,和boolean數組1個字節的定義,具體還要看虛擬機實現是否按照規範來,所以1個字節、4個字節都是有可能的。

- 2.如何保證同步

一段synchronized的代碼被一個線程執行之前,他要先拿到執行這段代碼的權限,在 java裏邊就是拿到某個同步對象的鎖(一個對象只有一把鎖); 如果這個時候同步對象的鎖被其他線程拿走了,他(這個線程)就只能等了(線程阻塞在鎖池 等待隊列中)。 取到鎖後,他就開始執行同步代碼(被synchronized修飾的代碼);線程執行完同步代碼後馬上就把鎖還給同步對象,其他在鎖池中 等待的某個線程就可以拿到鎖執行同步代碼了。這樣就保證了同步代碼在統一時刻只有一個線程在執行。
同步機制實現方式包括但不限於:
①ThreadLocal ② synchronized( ) ③ wait() 與 notify() ④ volatile

- 3.什麼是CAS

CAS的全稱是Compare And Swap 即比較交換,樂觀鎖,無鎖。其算法核心思想如下
執行函數:CAS(V,E,N)
其包含3個參數
V表示要更新的變量
E表示預期值
N表示新值

CAS操作需要我們提供一個期望值,當期望值與當前線程的變量值相同時,說明還沒線程修改該值,當前線程可以進行修改,也就是執行CAS操作,但如果期望值與當前線程不符,則說明該值已被其他線程修改,此時不執行更新操作,但可以選擇重新讀取該變量再嘗試再次修改該變量,也可以放棄操作

4.Spring IOC/DI 及其原理
Spring本身就是一個大的容器,來管理各種Bean,通常用來整合其它框架。優秀!
Ioc不是一種具體的技術,而是一種設計思想,Ioc的目的是爲了如何指導我們編寫出更加松耦合,更加優雅的程序。傳統的應用程序使我們在類的內部顯式的創建依賴的對象。從而導致類於類之間耦合度過高。而使用了Ioc的設計思想,將對象的創建,查找依賴,以及生命週期的控制權交給了Ioc容器。對象之間耦合較松,更加靈活。
IoC的一個重點是在系統運行中,動態的向某個對象提供它所需要的其他對象。這一點是通過DI(Dependency Injection,依賴注入)來實現的。DI通過反射實現

5.AOP是什麼,怎麼實現的
AOP面向切面編程,是對業務流程中某一類共性功能的橫向抽取。比如事務處理,消息通知。
Spring AOP中的動態代理主要有兩種方式,JDK動態代理和CGLIB動態代理。JDK動態代理通過反射來接收被代理的類,並且要求被代理的類必須實現一個接口。JDK動態代理的核心是InvocationHandler接口和Proxy類。

如果目標類沒有實現接口,那麼Spring AOP會選擇使用CGLIB來動態代理目標類。CGLIB(Code Generation Library),是一個代碼生成的類庫,可以在運行時動態的生成某個類的子類,注意,CGLIB是通過繼承的方式做的動態代理,因此如果某個類被標記爲final,那麼它是無法使用CGLIB做動態代理的。

6.單列索引和組合索引
聯合索引-使用結論:
1、查詢條件中出現聯合索引第一列,或者全部, 則能利用聯合索引.
2、條件列中只要條件相連在一起, 無論前後, 都會利用上聯合索引,
3、查詢條件中沒有出現聯合索引的第一列,而出現聯合索引的第二列,或者第三列,都不會利用聯合索引查詢。

單一列索引-使用結論:
1、只要條件列中出現索引列,無論在什麼位置,都能利用索引查詢.

優缺點比較:
1、索引所佔用空間:單一列索引相對要小.
2、索引創建時間:單一列索引相對短.
3、索引對insert,update,delete的影響程序:單一列索引要相對低.
4、在多條件查詢時,聯合索引效率要高.
索引的使用範圍:單一列索引可以出現在where 條件中的任何位置,而聯合索引需要按一定的順序來寫.

7.JVM以及GC
JVM分爲:虛擬機棧、本地方法棧、堆、方法區、程序計數器

本地方法棧用於支持native方法的執行,存儲了每個native方法的執行狀態。

虛擬機棧佔用的是操作系統內存,每個線程對應一個虛擬機棧,它是線程私有的,生命週期和線程一樣,每個方法被執行時產生一個棧幀(Statck Frame),棧幀用於存儲局部變量表、動態鏈接、操作數和方法出口等信息,當方法被調用時,方法的調用到結束對應着棧幀的入棧到出棧。

堆區是GC最頻繁的,也是理解GC機制最重要的區域。堆區由所有線程共享,在虛擬機啓動時創建。堆區主要用於存放對象實例及數組,所有new出來的對象都存儲在該區域。

方法區存放了要加載的類的信息(如類名、修飾符等)、靜態變量、構造函數、final定義的常量、類中的字段和方法等信息。方法區是全局共享的,在一定條件下也會被GC。當方法區超過它允許的大小時,就會拋出OutOfMemory:PermGen Space異常。

程序計數器是線程私有的,記錄正在執行的虛擬機字節碼指令地址。

判斷一個對象是否需要回收:引用計數法,可達性分析。
GC算法:複製算法,標記-清除,標記-整理
GC回收器:
新生代: serial,parnew,parallel(吞吐量優先)
老年代: serial old,parallel old,CMS
新生代+老年代:G1(官方推薦)

8.Dubbo的原理,如何運轉
Dubbo是阿里巴巴SOA服務化治理方案的核心框架,並被廣泛應用於阿里巴巴集團的各成員站點。
Dubbo是一個分佈式服務框架,致力於提供高性能和透明化的RPC遠程服務調用方案,以及SOA服務治理方案

0.服務容器負責啓動,加載,運行服務提供者。
1.服務提供者在啓動時,向註冊中心註冊自己提供的服務。
2.服務消費者在啓動時,向註冊中心訂閱自己所需的服務。
3.註冊中心返回服務提供者地址列表給消費者,如果有變更,註冊中心將基於長連接推送變更數據給消費者。
4.服務消費者,從提供者地址列表中,基於軟負載均衡算法,選一臺提供者進行調用,如果調用失敗,務消費者,從提供者再選另一臺調用。
5.服務消費者和提供者,在內存中累計調用次數和調用時間,定時每分鐘發送一次統計數據到監控中心。

9.Redis緩存穿透,緩存雪崩,緩存擊穿
緩存穿透,是指查詢一個數據庫一定不存在的數據。正常的使用緩存流程大致是,數據查詢先進行緩存查詢,如果key不存在或者key已經過期,再對數據庫進行查詢,並把查詢到的對象,放進緩存。如果數據庫查詢對象爲空,則不放進緩存.
解決方案:緩存空值,設置一個較短的緩存時間

緩存雪崩,是指在某一個時間段,緩存集中過期失效
解決方案:一般是採取不同分類,緩存不同週期。在同一分類中,加上一個隨機因子。這樣能儘可能分散緩存過期時間,而且,熱門類目緩存時間長一些,冷門類目緩存時間短一些,也能節省緩存服務的資源。

緩存擊穿,是指一個key非常熱點,在不停的扛着大併發,大併發集中對這一個點進行訪問,當這個key在失效的瞬間,持續的大併發就穿破緩存,直接請求數據庫,就像在一個屏障上鑿開了一個洞。
對於非常熱點的key直接設爲永不過期/mutex key互斥鎖

10.HashMap和ConcurrentHashMap
基於JDK1.8,ConcurrentHashMap、HashMap是基於Node<K,V>[]數組和鏈表/紅黑樹實現的。不同點在於HashMap線程不安全,ConcurrentHashMap通過使用CAS+Synchronized(1.8以前使用分段鎖)來保證線程安全的。

初始容量16,最大容量2^30,默認負載因子0.75,實際容量 = 初始容量負載因子(默認0.75) = 12,鏈表轉換樹的閾值默認8,樹轉鏈表閾值默認6。
HashMap的構造函數中,都直接或間接的調用了tableSizeFor函數。保證了取索引操作h&(length-1)的最後一位同時有爲0和爲1的可能性,保證了散列的均勻性。
①創建HashMap,初始容量爲16,實際容量 = 初始容量負載因子(默認0.75) = 12;
②調用put方法,會先計算key的hash值:hash = key.hashCode()。
③調用tableSizeFor()方法,保證哈希表散列均勻。
④計算Nodes[index]的索引:先進行index = (tab.length - 1) & hash。
⑤如果索引位爲null,直接創建新節點,如果不爲null,再判斷是否有元素
⑥如果有:則先調用hash()方法判斷,再調用equals()方法進行判斷,如果都相同則直接用新的Value覆蓋舊的;
⑦如果不同,再判斷第一個節點類型是否爲樹節點(涉及到:鏈表轉換成樹的閾值,默認8),如果是,則按照紅黑樹的算法進行存儲;如果不是,則按照鏈表存儲;
⑧當存儲元素過多時,需要進行擴容:

默認的負載因子是0.75,如果實際元素所佔容量佔分配容量的75%時就要擴容了。大約變爲原來的2倍(newThr =oldThr << 1);

11.ArrayList和LinkedList
ArrayList底層是通過數組實現的,繼承了AbstractList,初始容量爲10,在空參構造器中寫死的this(10)指定,線程不安全,ArrayList擴容,添加元素之前判斷是否需要擴容,擴容是1.5倍,使用Arrays.copyOf在原數據基礎上擴容

ArrayList是實現了基於動態數組的數據結構,LinkedList基於鏈表的數據結構,它繼承於AbstractSequentialList的雙向鏈表,由於AbstractSequentialList 實現了get(i)、set()、add() 和 remove()這些骨幹性函數,這也降低了List接口的複雜程度。

ArrayList與LinkedList都是不是同步的。如果多個線程同時訪問一個鏈接列表,而其中至少一個線程從結構上修改了該列表,則它必須保持外部同步。同步的方法就是使用Collections.synchronizedList(Collection c)來“包裝”該列表。

對於隨機訪問get和set,ArrayList絕對優於LinkedList,因爲從源碼可以看出,ArrayList想要get(int index)元素時,直接返回index位置上的元素;而LinkedList需要通過for循環進行查找,雖然LinkedList已經在查找方法上做了優化,比如index < size / 2,則從左邊開始查找,反之從右邊開始查找,但是還是比ArrayList(隨機查找)要慢。

從源碼來看,ArrayList想要在指定位置插入或刪除元素時,主要耗時的是System.arraycopy動作,會移動index後面所有的元素;LinkedList主耗時的是要先通過for循環找到index,然後直接插入或刪除。這就導致了兩者並非一定誰快誰慢!

12.如何設計一個接口
一.單一職責原則
二.里氏替換原則
只要父類出現的地方子類就一定可以出現,有子類出現的地方,

三、依賴倒置原則    
模塊間的依賴通過抽象發生,實現類之間不發生直接的依賴關係,其依賴關係是通過接口或抽象類產生的;
接口或抽象類不依賴於實現類
實現類依賴接口或抽象類

四、接口隔離原則
客戶端不應該依賴它不需要的接口
類之間的依賴關係應該建立在最小的接口上
概括 : 建立單一接口,不要建立臃腫龐大的接口,也就是接口儘量細化,接口中的方法儘量少

五、迪米特法則
迪米特法則也叫最少知識原則,含義是 一個對象應該對其他對象有最少的瞭解,這個應該很好理解,就是降低各模塊之間的耦合

六、開閉原則
模塊和函數應該對擴展開放,對修改關閉,開閉原則也是其他五個原則的基石

13.Js閉包是什麼

閉包指的是:能夠訪問另一個函數作用域的變量的函數。清晰的講:閉包就是一個函數,這個函數能夠訪問其他函數的作用域中的變量

14.非常大的數據量情況下有什麼比HashMap更好的數據結構
這個我不知道,據猜測,應該是TreeMap吧,時間複雜度O(logn),極限情況下,HashMap時間複雜度是O(n),最理想O(1)。

15.產生0-10000不重複隨機整數
個人想到兩種方案
一、先隨機出來1-10000的整數,將結果放入一個數組,如果隨機出來的數重複,繼續隨機。
這樣做的問題就是,當只剩下個別數字沒有隨機的時候,效率就會很低下
二、建一個1-10000的“數組”,隨機這個數組size大小範圍的數,取出該位置的數,數組移除這個數。
這樣做的話,感覺是維護數組的代價略大。
各位有什麼更好的方法的話,歡迎留言解惑。

16.SpringMVC和Spring Boot有什麼區別
SpringMVC是一個MVC模式的框架,Springboot就是極度簡化了spring、springMVC的配置,去掉了繁雜的配置文件,能夠快速搭建起一個web應用。

Spring 是一個“引擎”;
Spring MVC 是基於Spring的一個 MVC 框架 ;
Spring Boot 是基於Spring4的一套快速開發整合包。

17.SQL優化
1、查詢語句中不要使用 *
2、儘量減少子查詢,使用關聯查詢(left join,right join,inner join)替代
3、減少使用IN或者NOT IN ,使用exists,not exists或者關聯查詢語句替代
4、or 的查詢儘量用 union或者union all 代替
(在確認沒有重複數據或者不用剔除重複數據時,union all會更好)
5、合理的增加冗餘的字段(減少表的聯接查詢)
6、增加中間表進行優化(這個主要是在統計報表的場景,
後臺開定時任務將數據先統計好,儘量不要在查詢的時候去統計)
7、建表的時候能使用數字類型的字段就使用數字類型(type,status…),數字類型的字段作爲條件查詢比字符串的快
8、那些可以過濾掉最大數量記錄的條件必須寫在WHERE子句的最末尾

18.數據庫索引
數據庫索引是數據庫管理系統中的一個排序的數據結構,以協助快速查詢,更新數據庫表中數據,索引的實現通常使用B樹(B-tree)以及其變種B+tree(一些高效率的算法)

–使用索引時有些不生效的情況
1、使用like關鍵字模糊查詢時,% 放在前面索引不起作用,只有“%”不在第一個位置,索引纔會生效(like ‘%文’–索引不起作用)
2、使用聯合索引時,只有查詢條件中使用了這些字段中的第一個字段,索引纔會生效
3、使用OR關鍵字的查詢,查詢語句的查詢條件中只有OR關鍵字,且OR前後的兩個條件中的列都是索引時,索引纔會生效,否則索引不生效。
4、儘量避免在where子句中使用!=或<>操作符,否則全表掃描。
5、對查詢進行優化,應儘量避免全表掃描,首先應考慮在where以及order by涉及的列上建立索引。
6、應儘量避免在 where 子句中對字段進行表達式操作,否則全表掃描。
7、儘量避免在where子句中對字段進行函數操作,否則全表掃描。
8、不要在 where 子句中的“=”左邊進行函數、算術運算或其他表達式運算,否則系統將可能無法正確使用索引。
9、並不是所有的索引對查詢都有效,sql是根據表中的數據來進行查詢優化的,當索引列有大量數據重複時,sql查詢不會去利用索引
10、索引並不是越多越好,索引固然可以提高相應的 select 的效率,但同時也降低了 insert 及 update 的效率,
  因爲 insert 或 update 時有可能會重建索引,所以怎樣建索引需要慎重考慮,視具體情況而定。一個表的索引數最好不要超過6個,
11、儘量使用數字型字段,若只含數值信息的字段儘量不要設計爲字符型,這會降低查詢和連接的性能,並會增加存儲開銷。
  這是因爲引擎在處理查詢和連接時會 逐個比較字符串中每一個字符,而對於數字型而言只需要比較一次就夠了。
12、mysql查詢只使用一個索引,因此如果where子句中已經使用了索引的話,那麼order by中的列是不會使用索引的。
   因此數據庫默認排序可以符合要求的情況下不要使用排序操作,儘量不要包含多個列的排序,如果需要最好給這些列建複合索引。
13、order by 索引 ,不起作用的問題(除了主鍵索引之外):
  1、 如果select 只查詢索引字段,order by 索引字段會用到索引,要不然就是全表排列;
   2、如果有where 條件,比如where vtype=1 order by vtype asc . 這樣order by 也會用到索引!

19.分佈式環境如何保證session一致性
1.ngnix的iphash可以
2.使用spring-session框架來解決,底層採用重寫httpclient保證數據共享
3.使用token令牌代替session功能,把數據存放在redis中,每次從redis中獲取數據

20.有幾個非常大的文件,在不同服務器上,找出這些文件中出現頻率最高的幾條
根據網上類似的答案,都是對每一條數據取Hash值,最後再歸併。
希望有大佬能給個詳細解決方案,感激不盡!
 

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