Java後臺開發常見面試題
八種基本數據類型的大小,以及他們的封裝類
整數型: byte 1個字節 -128~127 封裝類:Byte short 2個字節 -32768~32767 Short Int 4個字節 -2147483648~2147483647 Integer long 8個字節 -2的63方~2的63次方-1 Long 浮點型: float 4個字節 單精度 Float Double 8個字節 雙精度 Double 布爾類型: boolean 4個字節 true或false Boolean 字符類型: char 2個字節 Character
引用數據類型:
分為3種,類、接口和數組
Switch能否用String做參數
在jdk7以前,switch只支持byte、int、short、char或者對應的包裝類和枚舉。
equals和==的區別
a) 對象類型不同 equals是超類Object的方法,而==是操作符 b) 比較類型不同 equals用來檢測兩個對象是否相同,即兩個對象的內容是否相等,==比較引用數據類型和基本數據類型時具有不同的功能。==比較的是變量(棧)內存中存放的對象的內存地址,用來判斷兩個對象的地址是否相同,即是否指向同一對象,比較的是真正意義上的指針操作,而equals用來比較的是兩個對象的內容是否相同,適用於所有對象。 c) 註意:如果沒有對該對象進行覆蓋的話,調用的仍然是超類Object的方法,而Object中的equals方法返回的是==的判斷。
自動拆裝箱和常量池
a) Java自動將原始數據類型值轉換成對應的對象,比如將int類型的變量轉換成Integer類型,自動裝箱時調用valueOf將原始數據類型轉換成對應的對象。 b) 反之,將Integer對象裝換成int類型值,這個過程叫拆箱,自動拆箱通過調用類似intValue、doubleValue這類的方法將對象轉換成對應的原始數據類型。 c) Java中的常量池,實際上分為兩種形態:靜態常量池和運行時常量池。 i. 靜態常量池:即.*class文件中的常量池,class文件中的常量池不僅僅包含字符串,還包含類、方法的信息,占用class文件絕大部分空間。 ii. 而運行時常量池:則是jvm虛擬機在完成類裝載過程後,將class文件中的常量池載入到內存中,並保存在方法區中,我們常說的常量池就是指方法區中的運行時常量池。
Object中有哪些公用方法?
a) Clone:實現對象的淺復制,只有實現了cloneable接口才可以調用此方法,否則會拋出CloneNotSupportedException異常。
b) Equals:在Object中和==是一樣的,子類一般需要重寫此方法。
c) Hashcode:該方法用於哈希查找,重寫了equals方法一般都要重寫hashcode方法,這個方法在一些具有哈希功能的collection中用到。
d) getClass:獲得運行時的類型。
e) wait:是當前線程等待該對象的鎖,當前線程必須是該對象的擁有者,也就是說具有該對象的鎖!
f) Notify:喚醒在對象上等待的某個線程。
g) notifyAll:喚醒該對象上等待的所有線程。
h) toString:轉換成字符串,一般子類都要重寫此方法,否則打印句柄。
Java的四種引用,強弱軟虛。
a) 強引用:最常見,把一個對象賦給引用數據類型則為強引用。如果內存中不足,java虛擬機將會跑出OutOfMemoryError錯誤,從而將程序異常停止強引用的對象是不可以gc回收的,不可以隨意回收具有強引用的對象來解決內存不足的問題。在java中,強引用是一種默認的狀態,除非Java虛擬機停止工作。
b) 軟引用:如果一個對象具有軟引用,內存空間足夠,垃圾回收就不會回收它,如果內存空間不足了,就會回收這些對象的內存。只要垃圾回收器沒有回收它,該對象就可以被程序繼續使用。軟引用用來實現內存敏感的高速緩存,比如網頁緩存或圖片緩存,使用軟引用能防止內存泄露,增強程序的健壯性。
c) 弱引用:用來描述非必需對象的,當jvm進行垃圾回收的時候,無論內存是否充足,都會回收被弱引用關聯的對象。
d) 虛引用:他不影響對象的生命周期,如果一個對象與虛引用關聯,則跟沒有與之關聯一樣,在任何時候都可能被垃圾回收器回收。
hashcode的作用
比較兩個對象是否相等,重寫的equals方法一般比較全面,比較復雜,效率比較低,而采用hashcode方法進行對比,只需要生成一個hashcode進行比較就可以了!
Hashmap中的hashcode的作用
a) Hashcode的存’用於查找的快捷性,如hashtable、hashmap等,hashcode是在散列結構中確定對象的地址。
b) 如果兩個對象相同,就是適用equals方法,那麽這兩個對象的hashcode一定要相同。
c) 如果對象的equals方法被重寫,那麽對象的hashcode也盡量重寫,並且產生hashcode使用的對象,一定要和equals放法使用的一致,否則會違反上面的第二點。
d) 兩個對象的hashcode相同,並不代表這兩個對象就相同,也就是不一定適用equals方法,只能說明這兩個對象在散列存儲結構中,如hashtable,他們“存放在同一個籃子裏”。
為什麽重載hashcode方法?
一般不需要重載hashcode方法,只有當類放在hshtable、hashmap、hashset等hash結構的集合時,才會重載hashcode。就hashmap來說,好比hashmap就是一個大內存塊,裏面有許多小內存塊,小內存裏面就是一系列的對象,可以利用hashcode查找小內存塊,,所以當equals相等時,hashcode必需相等,而且如果是Object對象,必須重載hashcode和equals方法。
Arraylist、linkedlist和vector的區別?
a) Arraylist:底層數據結構是數組,查詢快、增刪慢,線程不安全。
b) Liskedlist;底層數據結構是鏈表,查詢慢、增刪塊,線程不安全。
c) Vector:底層是數組,查詢慢、增刪慢,線程安全。
String、stringbuffer與stringbulder的區別?
a) String是不可變的對象,因此每次對string類型進行改變的時候,就等於生成了一個新的對象,然後蔣指針指向一個新的string的對象,因此經常改變內容的字符串最好不用string,因為每次生成對象都會對系統性能產生影響,特別是當內存中無引用對象過多時,jvm的gc就會開始工作,那麽速度一定會非常慢。
b) 而stringbuffer結果就完成不一樣了,每次結果都會對stringbuffer本省進行操作,而不是生成新的對象,再改變對象的引用。是線程安全的。
c) Stringbuildere是jdk5以後新增的,其用法和stringbuffer完全一致,但它是線程不安全的,在單線程中是最佳的,因為不需要維護線程的安全。
Map、set、list、queue、stack的特點與用法。
a) Map是鍵值對,鍵key是唯一不能重復的,一個鍵對應一個值,值可以重復,treemap可以保證順序,hashmap不保證順序,即是無序的,map可以把key和value單獨抽取出來,其中keyset()方法可以將所存的key抽取成一個set。而valuses方法可以將map中所有的value抽取成一個集合。
b) Set:不包含重復元素,且最多包含一個null元素,只能用iterater實現單向遍歷, set沒有同步方法。
c) List:有序的可重復集合,可以在任何位置增加和刪除元素。用Iterator實現單向遍歷,也可以用listIterator實現是雙向遍歷。
d) Queue:遵從先進先出原則,使用時盡量避免add()和remove()方法,而只是使用offer()來添加元素,使用poll來移除元素,它的優點是可以通過返回值來判斷是否成功,LinkedList實現Queue接口,Queue通常不允許插入null元素。
e) Stack:遵從先進後出原則,stack繼承自vector,它通過五個操作對類vector進行擴展,允許將向量視為堆棧,它提供push和pop操作,以及取堆棧頂點的peek()方法,測試堆棧是否為空的empty()方法等。
f) 用法:如果涉及堆棧、隊列等操作,建議使用list,對於快速插入和刪除元素,建議使用linkedlist,如果,快速隨機訪問元素,建議使用ArrayList。
Hashmap和hashtable的區別?
a) 都是map接口的實現類,都是基於hash表的實現類。
b) Hashmap集合線程不安全的類,不同步,執行效率高,允許鍵和值是null。
c) Hashtable集合是線程安全的類,同步,執行效率低,不允許鍵和值為null。
Jdk7和jdk8中的hashmap的實現。
a) Jdk7:hashmap底層維護一個數組,數組中的每一項都是一個entry,我們向hashmap中放置的對象實際上存儲在該數組中,map中的key和value則以entry的形式存放在數組中,而這個key放在數組的哪一個位置上,是通過key的hashcode來計算的。
b) Jdk8:采用(位桶+鏈表)紅黑樹的方式,也是非線程安全的。
Hashmap和hashConcurrentHashmap的區別,hashmap的底層源碼。
Hashmap是線程非安全的,效率比較高,hashtable和ConcurrentHashmap是線程安全的,效率比hashmap差一點,但ConcurrentHashmap采用了更高級的分段鎖機制,具體可以理解為把hashmap拆分為n個小的hashtable,根據key。Hashcode()來決定把key放到哪個hashtable中,在concurrenthashmap中,就是把map分為n個segment,put和get時,都是key.hashcode()算出放到哪個segment中。
接口和繼承的區別?接口內可以定義常量嗎?繼承可以繼承父類的那些東西?
a) 區別:
i. 標識符不同,interface和extends
ii. 接口支持多繼承,而不支持繼承的繼承
iii. 接口中只能定義全局變量和抽象變量,而繼承中可以定義屬性、方法、常量、變量等。
iv. 某接口被實現,在類中一定要實現接口所有的方法,而繼承只需要用哪一個就調用哪一個。
b) 接口不可以定義常量。
c) 繼承可以繼承父類所有的東西(成員方法、成員變量、包括私有)。
如何修改父類中以private關鍵字修飾的變量?
如果父類中有public的set方法,就可以通過set方法修改父類中以private修改的變量。
Java中public、private 、protect、default的區別?
a) Public:java中訪問限制最寬的修飾符,即公共的,被修飾的類、屬性、方法允許跨類訪問,甚至可以跨包訪問。
b) Private:是java中訪問限制最窄的修飾符,被private修飾的類、屬性、方法只能被本類的對象進行訪問,其子類不能訪問,更不允許跨包訪問。
c) Protec:介於public和private之間的一種訪問修飾符,一般稱受保護的,被其修飾的類、方法、屬性只能被本類和子類進行訪問,即使子類不在同一個包下。
d) Default:意為默認的,即不加修飾符,該模式下只能同一個包下進行訪問。
數據庫鎖的問題?如何上鎖?是不是行鎖?
a) 當多個用戶同時對數據庫進行操作時,會帶來數據不一致的問題,所以鎖主要是用於多用戶環境下保證數據庫完整性和一致性.
b) 鎖分類:從數據庫系統來看:排它鎖、悲觀鎖、更新鎖
從程序員角度來看:一種是樂觀鎖,一種是悲觀鎖。
i. 悲觀鎖:很悲觀,每次去拿數據的時候,都以為別人會修改,所以在每次拿數據的時候,都會上鎖,這樣別人拿這個數據就會block,直到它合鎖。具有強烈的排他性和獨占性,悲觀鎖的實現依靠數據庫提供的機制,也只有數據庫底層提供的機制才能保證數據訪問的排他性。傳統的關系型數據庫用到了很多這同樣的機制,比如行鎖、表鎖、讀鎖、寫鎖等,都是在操作前加上鎖。
ii. 樂觀鎖:很樂觀,每次去拿數據的時候都認為別人不會修改,所以不會上鎖,但是在更新的時候會判斷一下在此期間別人有沒有去更新這個數據,可以使用版本號等機制。悲觀鎖適用於多讀的應用類型,這樣可以提高吞吐量,像數據庫如果提供類似於write—condition機制的其實都是提供的樂觀鎖。
c) 按作用性質分:
i. 共享鎖:也叫讀鎖,用於所有只讀操作,不能同時增刪改,可以查。
例如:select * from 表 lock in share mode;
ii. 排它鎖:也叫讀鎖,表示對數據進行寫操作,一個事務對象施加了排它鎖,其他事務就不能加鎖了。
例如:查詢時加排它鎖,別人不能加共享鎖和排它鎖。
Select * from 表 for update;
僅允許一個事務封鎖此表,其他事務必須等到此鎖被釋放才能訪問。
排它鎖(x鎖)一直到事務結束才能釋放。
iii. 更新鎖:允許其他事務讀,但不允許在施加x鎖和u鎖,當要被讀取的對象要被更新的時候,則升級為x鎖,防止死鎖,如果一個數據在修改前直接申請更新鎖,在修改時再升級為排它鎖,就可以避免死鎖。
d) 按範圍分:
i. 行鎖:鎖的範圍是行級別,數據能夠確定哪些行需要鎖的情況下使用行鎖(inodb),如果在不知道會影響到哪些數據的時候就會使用表鎖
例如:一個用戶表有主鍵id和birthday。
Update …where id=? 行鎖
Update … where birthday=? 表鎖
ii. 表鎖:鎖的範圍是整張表。 MyISAM
22.事務的隔離性
a) 隔離性級別越低,並發性越好,但數據庫的一致性就越差。
隔離級別越高,並發性越差,但數據庫的一致性高。
b) 由低到高
讀未提交<讀提交<可重復讀(默認)<序列化讀
c) 錯誤的級別由低到高:
臟讀、不可重復讀、幻讀
臟讀:兩個事物,一個事務先修改,另一個事務讀,結果是修改前的結果。
不可重復讀:兩個事物,一個先讀是一個結果,一個後修改,再讀,又是一個結果。
幻讀:第一個事務表中有10、20、30、40幾個部門,第二個事務插入表中50的部門,然後提交,第一個事務插入50部門,主鍵沖突。
23.能否用一個sql語句解決庫存判斷問題(非查詢語句)。
用if語句:if(exper1,exper2,exper3)
如果exper1的值是true,則返回是exper2的值,如果exper1的值是false,則返回exper3的值。
例如:id name number
1 蘋果 300
2 梨 100
Update fruit set number=if(number>200,number,0)where if=’1’;
即如果蘋果的數量大於200,就不變,否則,number改為0,即就可以判斷內存是否充足。
24.紅黑樹
a) 特性:
i. 每個節點都是黑色或者紅色。
ii. 根節點是黑色。
iii. 定義null為黑色。
iv. 如果某個子節點是紅色,那麽它的兩個兒子都是黑色,且父節點一定是黑色。
v. 對於任意節點,它到葉子節點的每一條路徑都包含相同數目的黑色節點
性質5稱之為黑高。
b) 相對平衡:
i. 若H(left)>=H(right),則H(left)=2*H(right)+1
ii. 但BH(left)=BH(right),H(left)<H(right)同理。
c) 在調整節點p之前,必需保證p的左子樹left、右子樹right都已經是rbt。
i. 多個子問題成立->某個總問題成立
ii. 插入調整:刪除調整均是由底向上
d) Rbt的插入調整(默認是紅色)
i. 無需調整
- X為根節點,將x由紅染黑
- 父親節點是黑色
ii. 僅僅考慮父親節點p是紅色,由於性質4,爺爺節點必定是黑色,分為3中:
1. Case1:y為黑色,x可左可右;p、y染黑,g染紅;x回溯至g
2. Case2:y為黑色,x為右孩子,左旋p,x指向p,轉為case3
3. Case3:y為黑色,x為左孩子,p染黑,g染紅,右旋g結束。
Rbt的插入調整最多2次
右旋轉:逆時針旋轉兩個節點,使父親節點被右孩子取代,而自己變成左孩子。
左孩子:順時針旋轉兩個子節點,使父親節點被左孩子取代,自己變成右孩子。
25.Session是什麽?和cookie的區別?
a) Cookie通過客戶端記錄信息確認身份,session是通過服務端的信息確認身份。
b) 客戶端瀏覽器訪問服務器的時候,服務端把客戶端的信息以某種形式記錄在服務器上,這就是session,用戶與服務器建立連接的同時,服務器自動分配一個sessionid。
c) 區別:cookie不×××全,別人可以分析本地存在的cookie並進行cookie欺騙,考慮到安全應當使用session。
-
有哪些排序算法?說一下堆排序?時間復雜度是多少?
a) 直接插入排序:第一個元素已經排序,第二個與第一個元素進行比較,第一個大,第一個則與第二個交換位置,第三個分別於第一個和第二個比較,以此類推。 時間復雜度:O(n*n) b) 希爾排序:按步長grep進行分組,然後將每組元素利用直接插入排序的方法進行排序;每一次結束後再將步長grep減半,循環上述操作,直到步長grep=1,利用直接插入排序,完成排序。 時間復雜度:O(log n) c) 簡單選擇排序:首先在未排序序列中找到最小(或最大)的元素,放在排序序列的起始位置,然後再從未排序序列中找到最小(最大)的元素,放在已排序序列的後面。 時間復雜度:O(n*n) d) 堆排序:堆排序過程就是將待排序序列構造成一個堆,選出堆中最大的移走,再把剩下的整成堆,找出最大的在移走,重復直至有序。 i. 每次將根節點與左右節點最大的進行交換,直到根節點最大,然後把根節點放在最後一個位置,然後再次執行循環,找到最大值放在長度-1的位置。 ii. 時間復雜度:O(n log n) e) 冒泡排序:每次比較兩個元素,把小的放在前面。 時間復雜度:O(n*n) f) 快速排序:把一個序列分為兩個子序列,步驟可分為: i. 從數列中選出一個元素,作為基準。 ii. 重新排序數列,所有比基準序列小的元素放在基準前面,所有比基準大的元素放在基準後面,相同的放在任意一邊,在這個分區結束後,該基準處於中間位置。 iii. 遞歸將小於基準的子序列和大於基準的子序列排序。 iv. 即:先對大序列進行排序,大序列分為兩個子序列,然後遞歸調用方法對這兩個序列進行排序。 g) 歸並排序:將兩個或兩個以上的有序表合並成一個新的有序表,即把待排序序列分為若幹個子序列,每個子序列都是有序的,然後再把整個序列合並成整體有序序列。 時間復雜度:O(nlogn) h) 基數排序:將所有待比較的數(正整數統一為同樣的數位長度),數位數不足的前面補0,然後從低位開始,依次進行一次排序,這個序列從最低位排序一直到最高位排序完成以後,數列將變成一個有序序列。 時間復雜度:O(d*(n+r)) D為位數,r為基數,n為數據個數
27.Statement和preparestatement的區別?
a) 代碼的可讀性和可維護性preparestatement更好。
b) Preparestatement盡最大可能提高性能。
c) 提高安全性,preparestatement防止sql註入。
28.NIO和IO到底有什麽區別?有什麽關系?
a) NIO是以塊的方式處理數據,但是IO是以最基礎的字節流的形式去寫入和讀出的,肯定NIO的效率比IO的效率高出好多。
b) NIO不是和IO一樣用Ouputstream和Inputstream輸入流形式來處理數據,但是基於這種流的形式,而是采用通道和緩沖流的形式來處理數據的。
c) NIO通道可以是雙向的,IO中的流只能是單向的。
d) 還有就是NIO的緩沖區(其實也是一個字符數組)還可以進行分片,可以建立只讀緩沖區、直接緩沖區和間接緩沖區,只讀緩沖區很明顯就字面意思,直接緩沖區是為了加快I/O速度,而以一種特殊的方式分配其內存的緩沖區。
29.數據庫索引的分類,索引底層的實現,說一下b+樹,b-樹?
a) 索引的作用:
i. 提高查詢速度
ii. 確保數據的唯一性
iii. 可以加快表與表之間的連接,實現表和表之間的完整性。
iv. 使用分組和排序字句進行數據檢查時,可以減少分組和排序的時間。
v. 全文檢索字段進行搜索優化。
b) 分類;
i. 主鍵索引(PRIMAY_KEY):確保數據記錄的唯一性,一個表只有一個。
ii. 唯一索引(UNIQUE):避免一個表中某些數據列中的值重復。可以有多個。
iii. 常規索引(INDEX):快速定位特定數據。
iv. 全文索引(FULLTEXT):快速定位特定數據,只能用於MyISAM類型的數據表。
c) 索引底層實現:把平衡樹當做數據表默認的索引數據結構,平衡樹也就你、b+tree或者b-tree。
d) B-tree:適用於外查找的樹,是平衡樹的多叉樹。
i. 一個m階b樹是一顆平衡的m路搜索樹,它或者是空樹,或者滿足下列性質:
1. 定義任意非葉子節點最多有m個兒子,且m>=2;
2. 根節點的兒子數[2,m];
3. 除根節點以外的葉子節點的兒子數{m/2,m};
4. 每個節點存放m/2-1(向上取整)和至多m-1個關鍵字(至少2個)。
5. 非葉子節點的關鍵字個數=指向兒子的指針個數-1;
6. 非葉子節點的關鍵字:k[1]、k{2}…k[m-1],且k{i}<k{i+1}。
7. 非葉子節點的指針:p{1} 、p{2} 、p{3}、 p{4} …p{m},其中p[1】指向小於k[1]的子樹,p[m]指向關鍵字屬於k{i}和k{i+1}之間的子樹。
8. 所有子樹節點位於同一層。
ii. B-樹的特性:
1. 關鍵字集合分布在整棵樹中。
2. 任何一個關鍵字出現且只出現一個節點中。
3. 搜索可能在非葉子節點結束。
4. 其搜索性能等價於在在關鍵字全集中做一次二分查找。
5. 自動層次控制。
e) B+樹:
i. B+樹的定義:
1. 其定義與b-樹基本相同,除了:
2. 非葉子節點的子樹指針與關鍵字個數相同。
3. 非葉子節點的子樹指針p[i],指向關鍵字屬於k[i],k[i+1]的子樹。
4. 為所有關鍵字增加一個鍵指針。
5. 所有關鍵字在葉子節點出現。
ii. B+樹的特性:
1. 所有關鍵字都出現葉子節點的鏈表中(稠密索引)且鏈表中的關鍵字恰好是有序的。
2. 不可能在非葉子節點命中。
3. 非葉子節點相當於葉子節點的索引(稀疏索引),葉子節點相當於存儲數據(關鍵字)的數據層。
4. 更適合文件索引系統。
Java後臺開發常見面試題