文章目錄
- java面試題大彙總
- java基礎
- java的跨平臺原理
- JDK和JRE的區別
- == 和equals的區別
- 基本數據類型
- 面向對象的特徵
- java和C++的聯繫和區別
- 重載與重寫
- 裝箱與拆箱
- “==”與equals的區別
- 兩個對象的hashCode()相同,則equals()也一定爲true,對嗎?
- java中的Math.round(-1.5)等於多少
- String屬於基本數據類型嗎
- java中操作字符串有哪些類?他們有什麼區別?
- String str=“i”;與String str=new String("i");一樣嗎
- 如何將字符串進行反轉
- String的常用方法都有哪些
- 抽象類一定要有抽象方法嗎
- 普通類和抽象類有哪些區別
- 抽象類能使用final修飾嗎
- 接口和抽象類的區別
- java中的IO流分幾種
- BIO、NIO、AIO有什麼區別
- Files的常用方法有什麼
- JVM
- 容器
- java容器都有哪些
- Collection與Collections的區別
- List、Set、Map的區別
- HashTable和HashMap有什麼區別
- 如何決定使用HashMap還是TreeMap
- HashMap的實現原理
- HashSet的實現原理
- hashmap的初始容量爲什麼是2的冪次方
- hashmap擴容的加載因子爲什麼是0.75
- 鏈表長度達到多少時轉紅黑樹,是8嗎
- ArrayList和LinkedList的區別
- 如何實現數組和List的轉換
- ArrayList和Vector的區別是什麼
- Array和ArrayList的區別
- 在Queue中poll()和remove()的區別是
- 哪些集合類是線程安全的
- 迭代器Iterator是什麼
- Iterator怎麼使用,有什麼特點
- Iterator和ListIterator的區別
- 怎麼確保一個集合不能被修改
- 多線程
- JMM有了解嗎
- 並行和併發有什麼區別
- 線程和進程的區別
- 守護線程是什麼
- 創建線程有哪些方式
- 說一下runable和callable的區別
- 線程有哪些狀態
- sleep和wait的區別
- notify和notifyAll的區別
- 線程的run和start方法區別
- 創建線程池有哪些方法
- 線程池有哪些狀態
- 線程池中的submit方法和excute方法有什麼區別
- 在java中程序中怎麼保證多線程運行安全
- 多線程鎖的升級原理
- 什麼是死鎖
- 怎麼防止死鎖
- ThreadLocal是什麼,使用在什麼樣的場景
- 說一下synchronized的底層實現原理
- synchronized和volatile的區別
- synchronized和Lock的區別
- synchronized與ReentrantLock的區別
- 說一下atomic的原理
- 反射
- 對象拷貝
- java web
- get和post請求
- forward與redirect的區別
- jsp和servlet有什麼區別
- jsp有哪些內置對象?作用分別是什麼
- 說一下4種作用域
- session和cookie的區別
- 說一下session的工作原理
- 如果客戶端禁止cookie能實現session嗎
- 如何避免sql注入
- 異常
- 網絡
- http響應碼中301和302代表的是什麼?有什麼區別?
- forward和redirect有什麼區別
- 簡述tcp和udp的區別
- tcp爲什麼要三次握手
- OSI的七層模型有哪些
- get和post的區別
- 如何實現跨域
- 說一下jsonp的實現原理
- 設計模式
- spring/spring mvc
- 爲什麼要使用spring
- 解釋一下什麼是aop
- 解釋一下什麼是ioc
- spring有哪些主要的模塊
- spring中常用的注入方法有
- spring中的bean是線程安全的嗎
- spring中支持幾種bean作用域
- spring的事務實現方式有哪些
- 說一下spring mvc的運作流程
- spring mvc有哪些組件
- @RequestMapping的作用是什麼
- @Autowired的作用是什麼
- spring boot/spring cloud
- mybatis
- mybatis中的#{}和${}是什麼區別
- mybatis有幾種分頁方法
- RowBounds是一次性查詢全部結果嗎?爲什麼
- mybatis邏輯分頁和物理分頁的區別
- mybatis是否支持延遲加載?延遲加載的原理是什麼
- 說一下mybatis的一級緩存和二級緩存
- 數據庫
java面試題大彙總
進行一次java相關面試題的大綜合。
下面是可能涉及到的模塊。
java基礎
java的跨平臺原理
java的跨平臺原理靠的是jvm(java虛擬機)。不同的操作系統提供了不同版本的jvm,jvm以此來屏蔽不同操作系統的指令差異,只要在不同的操作系統中安裝不同的jvm就可以把java應用程序放在不同的操作系統上去運行。
JDK和JRE的區別
JRE是java運行環境,是供java應用程序的用戶使用的。
JDK是java開發工具,是供java開發人員使用的。包含了JRE和java的編譯器
== 和equals的區別
==對於基本數據類型來說直接比較數值,對於引用類型來說比較的是其內存首地址;
equals比較的是內存中存的值是否相同。對於我們自定的類使用這個方法需要重寫實現,不然效果和==是一樣的。
基本數據類型
java基本數據類型有8種:
基本數據類型 字節數 byte 1 short 2 int 4 long 8 float 4 double 8 char 2 boolean 1
面向對象的特徵
面向對象的特徵有4個:抽象、封裝、繼承、多態
- 抽象:將現實生活中的對象某些共有的特徵抽象成屬性,行動抽象成方法
- 封裝:將屬性和方法封裝在一個模塊中,也就是一個類
- 繼承:一個類可以派生出子類,子類可以繼承父類所有非私有的屬性和方法,還可以進行擴展
- 多態:對象調用的方法在編譯時是無法確認的,只有在運行的時候纔會確認。體現在重寫和重載
java和C++的聯繫和區別
聯繫:都是面向對象的語言,都具有面向對象的特點:抽象、封裝、繼承、多臺
區別:
- 指針:java中不提供指針來直接訪問內存,更加安全
- 繼承:java是單繼承的,而C++允許多繼承
- 內存:java中有自動內存管理機制,不需要我們手動去調用函數進行內存回收
重載與重寫
1.重載:相同的函數名,參數不同(參數類型,個數,順序不同)
- 重寫:繼承關係中,子類對父類某方法的重寫
裝箱與拆箱
裝箱:將基本數據類型轉換成包裝類型
拆箱:將包裝類型轉換成基本數據類型實際上,運行時會進行自動裝箱拆箱
“==”與equals的區別
- ==,對於基本數據類型,直接進行比較,對於引用類型的對象,比較的是內存的首地址是否相同
- equals,比較的是內存中存儲的值是否相同。
原因:基本數據類型直接存儲在棧中,引用類型存儲在棧中,其存儲地址存儲在棧中
兩個對象的hashCode()相同,則equals()也一定爲true,對嗎?
不對。hashCode一樣只是兩者在內存中存儲的首地址是一樣的,但是值不一定一樣。
final在java中的作用
final是java中的修飾詞,可以修飾變量、方法、類。修飾變量標識變量的值時常量,不需進行初始化且不可改變,修飾方法標識方法不可被重寫,修飾類標識類不可以被繼承。
java中的Math.round(-1.5)等於多少
-1
String屬於基本數據類型嗎
不屬於
java中操作字符串有哪些類?他們有什麼區別?
String,StringBuilder,StringBuffer.
String的內容不可更改,StringBuilder和StringBuffer的內容是可以更改的;
StringBuilder是線程不安全的,StringBuffer是線程安全的。
String str=“i”;與String str=new String(“i”);一樣嗎
分配內存的方式不一樣。第一種分配在常量池中,會先在字符常量池中尋找有沒有一樣值的字符串,若有了就直接指向該地址,沒有的話會先在常量池新建一個,再進行地址指向;
而第二種會在堆內存新建一個對象,再進行指向。
如何將字符串進行反轉
可以使用StringBuilder或者StringBuffer的reserve方法進行反轉
String的常用方法都有哪些
equals方法比較兩個字符串的值是否一樣;
charAt方法輸出指定索引處字符;
getBytes方法得到字符串的字節類型的數組
indexOf方法得到指定字符的索引
replace方法進行字符替換
trim方法可以去掉字符串前後的空格
split方法可以分割字符串,返回分割後的數組
length方法返回字符串長度
toLowerCase返回轉變爲小寫之後的字符串
toUpeerCase返回轉變爲大寫之後的字符串
substring截取字符串
抽象類一定要有抽象方法嗎
不一定
普通類和抽象類有哪些區別
抽象類不能直接進行實例化,普通方法可以
普通類不可以含有抽象方法,抽象類可以含有抽象方法
抽象類能使用final修飾嗎
不能。因爲final修飾過的類不能重寫,而抽象類不重寫就沒法進行抽象方法的實現
接口和抽象類的區別
抽象類可以有構造器,而接口不可以有構造器
抽象類中的修飾符可以是任意的,而接口是可以是public的
java中可以多實現接口,但是隻可以單繼承抽象類
java中的IO流分幾種
根據功能來分:輸入流輸出流;
根據類型分:字節流字符串;
BIO、NIO、AIO有什麼區別
BIO:Block IO同步阻塞式IO,是我們平時使用的傳統的IO
NIO:New IO同步非阻塞IO,客戶端服務端通過通道Channel通訊,實現了多路複用
AIO:Asynchronized IO異步非阻塞IO
Files的常用方法有什麼
exists方法判斷路徑是否存在
createFile創建文件
createDicrectory創建文件夾
delete刪除一個文件或目錄
copy複製文件
move移動文件
size查看文件個數
read讀取文件
write寫入文件
JVM
JVM組成
jvm主要組成:類加載器、運行時數據區、執行引擎、本地庫接口
運作:由類加載器將class文件加載到內存中,運行時數據區是代碼中變量存儲運作的地方,相對應的執行引擎將字節碼文件轉爲相對應的底層系統指令,交給cpu去執行,在執行的時候可能調用到本地庫接口。
類加載機制
類加載機制是什麼
虛擬機把描述類的數據從class字節碼文件加載到內存中,並進行數據的校驗、轉換解析和初始化,最終形成可以在jvm上運行的類型的過程就是類加載機制
類加載的加載過程(生命週期)
加載、驗證、準備、解析、初始化
加載過程是:加載、連接、初始化;
其中連接的過程是:驗證、準備、解析
加載:jvm將字節碼文件轉化爲二進制字節流,並加載到內存中
驗證:驗證字節流中包含的信息符合虛擬機的要求並且是安全的
準備:爲類變量分配內存並且初始化值
解析:對類、接口、字段、方法等進行解析;將常量池中的符號替換轉化爲直接引用
初始化:收集類所有字段的賦值動作和靜態代碼塊
類加載器
類加載器負責將class的字節碼文件轉換成類實例。
類加載器有三種:啓動(Boostrap)類加載器、拓展(ext)類加載器、系統(system)類加載器
確定類的是否相等,除了判斷權限類名之外,還要判斷是不是由一個類加載器加載的。
雙親委派模型
當一個類需要被加載時,不是由本身的類加載器去加載的,而是向父類加載器發起請求去加載,依次向上請求,只有當父類無法完成加載時才向下傳遞給子類加載器去處理。
運行時數據區
jvm的內存結構
jvm的內存結構由虛擬機棧、堆、方法區、程序計數器和本地方法棧構成的,其中堆和方法區是線程共享的,其他的三個是線程獨有的。
如下圖:
方法區:主要存儲類信息、常量池、編譯後的字節碼等數據
堆:存放初始化的對象和數組
棧:棧的結構是棧幀組成的,一個方法對應一個棧幀。棧幀中存有局部變量表,操作數棧,方法出口等信息
本地方法棧:主要是爲一些native方法服務
程序計數器:記錄當前程序執行指令的行數
說一下堆棧的區別
棧中存儲的是局部變量,堆中存的是實體;
因爲局部變量的生命週期比較短,所以棧內存更新速度比堆快;
堆中局部變量使用完了之後就會被立即釋放,而堆中的數據是回收機制不定期回收的
堆分區及其垃圾回收機制
堆中分爲新生代和老年代,新生代中又分爲一個Eden區和兩個(倖存)survivor區,survivor區分爲from和to兩個。
Eden區是新建對象存放的區域,當觸發一次monitor gc時,會將Eden區存在的數據和survivor from區存在的數據複製到survivor to區,然後清理Eden區和survivor from區的垃圾。
每一個對象的對象頭中有一個標識年齡的字段,每一次這樣的monitor gc,對象的年齡都會加1,當年齡達到15(默認情況下)時,會將對象轉移到老年代中去,當老年代滿了,會觸發full gc。
堆內存的分區比例及參數配置
新生代:老年代=1:2;通過參數
-XX:NewRatio
配置Eden:from:to = 8:1:1 ;通過參數
-XX:SurvivorRatio
配置新生代的對象唄複製15次會進入老年代; 通過參數
-XX:+mAXtENURINGtHRESHOLD
配置
GC
GC怎麼判斷對象是可被回收的垃圾
方法一:引用計數法,當對象被引用的時候+1,引用取消-1,計數爲0的對象可以被回收;但是循環引用的情況無法解決;
方法二:可達性分析法:一般設定棧中的對象引用爲GC Roots引用,用GC Roots向下搜索,指向被引用的對象,稱爲引用鏈;當對象沒有Root引用時可以被回收
GC的垃圾回收算法有:
有四種:標記清除、複製、標記整理、分代
標記清除:遍歷內存,對可以回收的對象進行標記,然後再回收。會引起空間碎片化的問題
複製算法:將內存劃分爲兩個部分,第一個部分進行垃圾回收時,將可用的對象複製到另外一個部分後,進行第一部分的全清除。以空間換時間,空間利用率低
標記整理:將可用的對象標記起來,然後移動到內存的一端,再對剩下的空間進行清理
分代算法:在java的堆內存中使用分代算法,分爲新生代和老年代。新創建的對象放在新生代的Eden區,新生代垃圾回收時使用的是複製算法;存活久的對象會移動到老年代,老年代中使用的是標記整理算法。
垃圾回收器
常見的幾種垃圾回收器:(主要記住cms和G1)
- serial垃圾回收器:單線程的垃圾回收器,回收時其他任務都會停下來,使用複製算法
- parNew垃圾回收器:serial的多線程版本,但是也需要stop the world,使用複製算法
- CMS(concurrent mark sweep):標記清除算法,是一種以獲得最短回收停頓時間爲目標的收集器。使用標記清除算法。會產生大量的空間碎片
- G1收集器:標記整理算法實現。
四種引用類型
四種引用類型:強引用、弱引用、軟引用、虛引用
- 強引用:一直到jvm關閉纔會回收的對象。在內存不足的情況下,內存寧願拋出異常也不會回收;
- 軟引用:當內存充足的時候不會回收,當內存不足了就會回收
- 軟引用:只要垃圾回收器掃描到它,就會被回收
- 虛引用:維護一個隊列,被回收的引用放入隊列中,用來跟蹤對象唄回收的活動
引用類型 被回收時間 用途 生存時間 強引用 從來不會 對象的一般狀態 jvm停止運行時 弱引用 jvm垃圾回收時 對象緩存 gc運行後 軟引用 內存不足時 對象緩存 內存不足時 虛引用 未知 未知 未知
重排序
jvm自行優化的一種手段。在單線程中不影響運行結果的情況下,jvm可能會將底層的指令重排序進行優化。然而在多線程的情況下,就可能會影響運行的結果。
?內存屏障
?happen-before原則
jvm的配置參數
堆棧配置相關
-Xmx3550m
:最大堆大小爲3550m
-Xms3550m
:設置初始堆大小爲3550m
-Xmn2g
:設置年輕代大小爲2g
-Xss128k
:設置每個線程的堆棧大小爲128k
-XX:MaxPermSize=16m
:設置持久代(方法區+其他)大小爲16m
-XX:NewRatio=4
:設置新生代和年老代的比值
-XX:SurvivorRatio=4
:設置Eden區和一個survivor區的 比值
-XX:MaxTenuringThreshold=0
:這隻對象多少歲進入老年代
查看堆棧情況的指令
jstack pid
容器
java容器都有哪些
ArrayList、LinckedList、Vector、HashSet、HashMap、HashTable、ConcurrentHashMap
集合的大分類
集合的分類有兩種:
- Collection:只存儲值value
- Map:存儲鍵值對key-value
Collection
Collection只存儲值value,這種存儲方式的集合有兩類:
- List:有序的,可重複的
- Set:無序的,不可重複的
List
List存儲的數據是有序的,可重複的,派生了兩種子類:
- ArraysList:底層實現是數組
- LinkedList:底層實現是鏈表
一、 ArraysList
底層實現是數組,查找快,插入和刪除效率較低
二、 LinkedList
底層實現是鏈表,查找慢,插入和刪除效率較高
數組和鏈表的區別:
- 存儲位置的不同:數組相鄰位置的元素在物理空間上也是相鄰的,而鏈表不一定(可能相鄰,也可能不相鄰);
- 存儲空間的不同:數組要求一片連續的空間來存儲每一個元素,可能會造成空間的浪費,而鏈表不一定要連續的空間,可以利用零碎的空間;
- 在操作的效率上:數組查找特定的元素效率比較高(因爲可能根據下標索引直接查找到元素),但插入和刪除操作效率比較低(因爲需要對元素挨個進行移動);而鏈表的插入和刪除操作效率比較高(只需要更改next空間的指向即可),查找效率低(因爲需要從第一個元素開始一個一個找到目標元素)
Set
Set存儲的數據是無序的,不可重複的。常用的子類有:
- HashSet:無序的
- LinkedHashSet:有序的,根據插入的順序排序
Map
Map存儲數據是以鍵值對key-value形式來存儲的。其中key值不可以重複。
Map常用的子類有:
- HashMap
- HashTable
- ConcurrentHashMap
HashMap
- HashMap可以把null作爲key值和value值
- HashMap是線程不安全的,效率高
HashTable
- HashTable不可以把null作爲key值和value值
- HashTable是線程安全的,效率低
CurrentHashMap
CurrentHashMap既保證了線程安全,又保證了效率
Collection與Collections的區別
Collection是java中的一個集合接口,提供了一些對集合進行基本操作的方法,直接實現類有List和Set;
Collections是工具類,提供了許多方法對集合進行操作,如排序、搜索、線程安全等。
List、Set、Map的區別
List和Set是Collection的子類,存的是單個的值,Map是以鍵值對的形式存儲的
List是有序的可重複的,Set是無序的不可重複的
HashTable和HashMap有什麼區別
一是HashMap允許以null作爲鍵和值,而HashTable是不允許的
二是HashMap是線程不安全的,HashTable是線程安全的
如何決定使用HashMap還是TreeMap
若要對Map進行插入刪除操作時,應當使用HashMap,而若有排序需求的應當使用TreeMap
HashMap的實現原理
HashMap在jdk1.8之前是以數組+鏈表的形式實現的,在1.8之後是以數組+鏈表+紅黑樹的形式實現的
HashSet的實現原理
HashSet是以HashMap實現的。HashSet的值存在hashMap的key值中
hashmap的初始容量爲什麼是2的冪次方
hashmap進行hash運算的時候是用&位運算的方式,使用2的指數次進行位與計算髮生衝突的概率相對比較低,使得元素可以相對均勻地進行存儲,從而提高訪問的效率。
hashmap擴容的加載因子爲什麼是0.75
0.75是時間利用率和空間利用率的一個平衡,若使用較高的負載因子,雖提高了空間利用率,但是hash衝突過多,不利於訪問,犧牲了時間利用率;當負載因子過低時,衝突較少,提高了訪問的效率,但是需要的空間比較大,犧牲了空間利用率。因此,採用了兩者平衡的一個負載因子0.75
鏈表長度達到多少時轉紅黑樹,是8嗎
當數組長度小於64時候,優先進行擴容;
當數組長度大於64後,在進行轉紅黑樹之前會先把節點插入鏈表中,所以實際上應該是9
ArrayList和LinkedList的區別
ArrayList底層是以數組來實現的,LinkedList的底層是以雙向鏈表來實現的。所以ArrayList的查詢效率較高,插入和刪除的效率較低,而LinkedList的查詢效率較低,插入和刪除的效率較高
如何實現數組和List的轉換
List轉數組:toArray方法
數組轉List:asList方法
ArrayList和Vector的區別是什麼
Vector是線程安全的,而ArrayList並不能保證線程的安全,所以ArrayList的性能更好
Array和ArrayList的區別
數組的長度不可改變,而ArrayList的長度是可以延長的
數組可以容納基本數據類型,也可以容納對象,而ArrayList只可以容納對象
數組沒有提供列表那麼多的方法
在Queue中poll()和remove()的區別是
poll方法在獲取元素失敗的時候會返回空,而remove會拋出異常
哪些集合類是線程安全的
Vector、HashTable、stack、enumeration(枚舉,相當於迭代器)
迭代器Iterator是什麼
迭代器是用來對集合進行遍歷使用的
Iterator怎麼使用,有什麼特點
調用Collection下的實現類提供iterator方法來獲得Iterator類的實例,使用next方法可以獲得下一個元素,而hasNext檢查序列中是否還有可遍歷的元素
Iterator和ListIterator的區別
ListIterator只可以使用在ArrayList上,而Iterator可以在Set和List中使用
Iterator只可以單向遍歷,而ListIterator既可以向前也可以向後
怎麼確保一個集合不能被修改
使用Collections下的unmodifiablexxx方法返回的集合時不可以被修改的,修改會報錯,如unmodifiableMap、unmodifiableList、unmodifiableSet
注:不能使用final來實現,因爲final修飾變量若是基本數據類型值不能修改,而修飾引用類型是地址不可修改,但是值可以修改,集合都是引用類型的。
多線程
JMM有了解嗎
JMM是對於多線程的java內存模型。在JMM中,臨界資源、共享變量在主內存中,每個線程將他們要用的變量複製一份副本到自己的本地工作內存中進行操作。在JMM中有8種基本的原子操作,分別是lock、read、load、use、assig、store、write、unlock
並行和併發有什麼區別
並行是指多個事件發生在同一時刻,如多個任務在多個cpu或者一個cpu的多個核上同時進行;
併發是一個時刻只有一個事件發生,但同一時間間隔發生多個事件,如一個cpu時間片切換進行
線程和進程的區別
進程是運行中的程序,是系統進行資源分配的調度的基本單位,一個進程中可以有一個或多個線程,線程是爭奪CPU時間片的基本單位。
各進程都有自己獨立的內存空間,而一個進程中的線程之間共享內存空間,所以進程之間的切換沒有線程那麼快
守護線程是什麼
守護線程是在程序運行時在後臺提供一種通用服務的線程。
創建線程有哪些方式
- 繼承Thread方法
- 實現Runable接口
- 實現Callable接口
- 線程池
說一下runable和callable的區別
runable需要實現的是run方法,callable需要實現的是call方法;
callable可以得到返回值,而runable沒有返回值
線程有哪些狀態
新建、就緒、運行、阻塞、死亡
sleep和wait的區別
sleep是Thread中的方法,wait是Object中的方法
sleep不釋放鎖,而wait會釋放鎖
notify和notifyAll的區別
notify只是隨機喚醒一個線程,而notifyAll會喚醒所有等待的線程,再讓他們自己去競爭cpu時間片
線程的run和start方法區別
start方法是用來喚醒線程的,喚醒之後的線程進入就緒狀態,而獲得時間片的線程再去執行run方法,run方法是線程的執行體
創建線程池有哪些方法
- newFixedThreadPool
創建一個固定長度的線程池,當提交一個任務就創建一個線程,直到達到線程的最大數量後線程數量將不再發生變化,當線程發生異常結束時,線程池會補充一個新的線程
- newCacheThreadPool
創建一個可緩存的線程池,線程池的數量不受限制,當線程的數量超過了處理的需求時候,就回收空閒的線程,當有新的需求時候就創建新的線程
- newSingleThreadExcutor
單線程的線程池,只創建一個線程來執行任務,當線程發生異常結束時,創建一個新的線程來替代。按照任務在隊列中的順序來串行執行。
- newScheduledThreadPool
創建一個固定長度的線程池,而且以延遲或定時的方式來執行任務。
線程池有哪些狀態
- running:剛創建的線程池就處於Running狀態
- shutdown:不接受新的任務,但是能處理已排隊的任務
- stop:不接受新的任務,不處理已排隊的任務,中斷正在處理的任務
- tidying:當shutdown狀態的線程池中任務數爲0後進入tidying狀態
- terminated:線程池徹底終止
轉換圖:
線程池中的submit方法和excute方法有什麼區別
submit方法的參數可以是Runable接口的,也可以是Callable接口的,而excute參數只能是runable接口的;
submit方法有返回值,而excute方法沒有返回值;
submit中拋出異常會內部處理,而excute需要我們try catch
在java中程序中怎麼保證多線程運行安全
多線程安全問題體現在:原子性、可見性和有序性
Atomic、synchronized、Lock可以解決原子性
synchronized、Lock和volatile可以解決可見性問題
Happens-Before規則可以解決有序性問題
多線程鎖的升級原理
多線程鎖從低到高有:無鎖、偏向鎖、輕量級鎖、重量級鎖
在鎖對象的對象頭裏有一個ThreadId,在鎖的創始狀態下,ThreadId是空的,當下是無鎖狀態,當有線程獲得鎖時,ThreadId中存該線程的Id,升級爲偏向鎖,當有其他的線程爭奪鎖時,偏向鎖升級爲輕量級鎖,而線程通過自旋繼續獲取鎖,執行了一定的次數還沒有得到鎖之後,就會升級爲重量級鎖。
什麼是死鎖
死鎖是多個進程相互等待的一種僵局狀況
怎麼防止死鎖
死鎖發生有四個條件:互斥、請求與保持、不可剝奪、循環等待
要防止死鎖需要破壞這些條件,互斥條件是資源使用的原則,不能破壞;
破壞請求與保持條件:線程一次性獲得所有他要用的資源
破壞不可剝奪條件:進程不能獲得所需的全部資源時就進行等待,並且要釋放已經獲得的資源給其他進程使用
破壞循環等待條件:將資源進行編號,緊缺資源編大號,進程按編號次序申請資源,要申請大號資源首先要獲得小號的資源
ThreadLocal是什麼,使用在什麼樣的場景
ThreadLocal是爲線程提供獨立的變量副本,使每個線程都能夠獨立地改變屬於自己的副本,而不影響其他線程所對應的副本。
常用於數據庫連接和session管理等
說一下synchronized的底層實現原理
synchronized底層是用監視器monitor來實現的,其中有兩個指令,一個是monitorenter,一個是monitorexit,分別是進入鎖和退出鎖的指令。
synchronized和volatile的區別
synchronized是線程安全的,可以保證原子性,而volatile無法保證原子性
synchronized和Lock的區別
synchronized是基於JVM的關鍵字,而Lock是API層面的接口
synchronized在遇到異常時會自動釋放鎖,而Lock需要我們手動釋放鎖,否則會發生死鎖的現象
synchronized是不能中斷的,而Lock可以使用interrupt方法中斷
synchronized無法獲得鎖的獲取狀態而Lock可以
synchronized與ReentrantLock的區別
synchronized是一個關鍵字,ReentrantLock是Lock的一個實現類,ReentrantLock包括了synchronized中的所有功能,還進行了擴展;
說一下atomic的原理
會調用unsafe類中的一些方法來對底層進行操作
反射
什麼是反射
反射是在運行的時候可以獲取到任意類名稱,所有屬性、方法、註解、類型、類加載器等
什麼是java序列化?什麼情況下需要序列化
序列化是將對象轉化爲字節流的過程;
當java對象需要在網絡中傳輸或持久化存儲在文件中時,就需要用到序列化。
動態代理是什麼?有哪些應用
動態代理,是在運行的時候動態地創建目標類,可以調用和擴展目標類的方法。
常使用的場景有:Spring的AOP、事務、權限、日誌。
怎麼實現動態代理
首先需要定義一個接口,然後要有一個實現InvocationHandler的類的處理類;
第二種方式是使用CGLIB,先要引入相關的jar包
對象拷貝
爲什麼要使用對象克隆
當我們需要操作對象,但是卻希望保留之前的數據時,可以使用克隆
如何實現對象克隆
方法一:實現Cloneable接口並重寫clone方法進行克隆
方法二:實現Serializable接口,通過對對象的序列化和反序列化來實現克隆,可以實現真正的深克隆
深拷貝和淺拷貝的區別
淺拷貝只拷貝到基本數據類型,而對於對象類型拷貝的是其地址,更改會影響到原對象;
深拷貝不僅拷貝了基本數據類型,對於對象類型也會拷貝一份副本,更改不會影響到原對象。
java web
get和post請求
自己理解:他們都是http的請求方式。get、post、put、delete分別對應着對資源的查、改、增、刪操作。所以,get主要用來對資源的獲取/查詢,post主要用來對資源進行更新的操作。
回答:
- GET請求的數據會在地址欄顯示出來,而POST請求的數據不在地址欄中,而是包在http的包體中
- 由於1,GET請求的數據多少有限制(地址欄的長度有限制),而POST的請求數據的數量沒有限制
- 由於1,GET請求的安全性沒有POST的高
怎麼編寫Servlet
實現HttpServlet類,重寫doGet或者doPost方法,也可以重寫service方法來調用相應的doGet或doPost方法來完成對請求的響應。
Servlet的生命週期
- 服務器啓動後,加載並實例化servlet
- servlet通過調用init方法進行初始化
- 請求來的時候,調用service方法處理客戶端的請求
- 服務器關閉,通過調用destroy方法來銷燬servlet
- java的垃圾回收機制進行空間回收
forward與redirect的區別
- forward服務器端發起的請求。瀏覽器的地址不會改變,只是將請求到的數據include進來
- redirect客戶端發起的請求。redirect會使瀏覽器跳轉到新的地址,加載一個新的頁面
jsp和servlet有什麼區別
jsp是一種特殊的servlet,jsp最終也會被翻譯成servlet;
jsp側重於視圖,而servlet側重於業務邏輯;
另外,jsp是在前端代碼中插入java語言代碼,而在servlet中要寫入前端代碼需要用write來拼接前端代碼,比較麻煩。
jsp有哪些內置對象?作用分別是什麼
request:封裝客戶端的請求
response:封裝服務器端對客戶端的響應
session:封裝會話的對象
application:風咋混個服務器運行環境的對象
page:jsp對象本身
pageContext:可以通過該對象獲得其他對象
config:web應用的配置對象
out:輸出服務器響應對象的輸出流
excetion:封裝頁面拋出的異常對象
說一下4種作用域
page的作用範圍是一個頁面;
application的作用範圍是整個應用程序
session的作用範圍是一次會話中
request的作用範圍是一次請求
session和cookie的區別
session和cookie都是用於會話跟蹤技術的;session的實現依賴於cookie,因爲cookie中存有一個sessionId來標識session
session將數據存在服務器端,而cookie將數據存儲在客戶端
所以session的安全性高於cookie
說一下session的工作原理
session是一個存在服務器端的一個類似於散列表格的文件。相當於一個map,鍵值存sessionId
如果客戶端禁止cookie能實現session嗎
可以手動在url中加入sessionId,或者將sessionId存在數據庫或文件中來實現
如何避免sql注入
使用prepredStatement來傳參數
使用正則表達式來過濾參數
jsp頁面中檢查是否包含非法字符
異常
throw和throws的區別
throws是用在方法上的,後聲明可能出現的異常類;
而throw用在方法中,用來拋出異常
final、finally、finalized的區別
final是修飾詞,用來修飾變量表示變量的值不可改變,修飾方法表示方法不可被重寫,修飾類表示類不可被繼承;
finally是在異常處理中使用的,用finally包含的代碼塊無論是否發生異常都會運行
try-catch-finally中,如果catch中return了,finally還會執行嗎
會,在return之前先執行finally的代碼
常見的異常類有哪些
空指針異常;數組越界;找不到類;類型轉換異常;sql異常等
網絡
http響應碼中301和302代表的是什麼?有什麼區別?
301和302都表示url發生了轉移
301表示永久地轉移;302表示暫時性的轉移
forward和redirect有什麼區別
forward是由服務器端發生的一次請求,實現局部的刷新,地址欄不會改變;
redirect相當於客戶端發起的兩次請求,是重新加載了一個頁面,地址欄會改變
簡述tcp和udp的區別
tcp是面向連接的,udp是無連接地發送數據;
tcp保證了可靠性,而udp不保證可靠性;
udp保證實時性;
tcp是點到點的,而udp支持一對一,一對多,多對多的交互通信
tcp爲什麼要三次握手
爲了實現可靠數據傳輸,通信雙方都要維護一個序列號,三次握手,既要保證發送方發送出了正確的數據,又要保證接收方接收到了正確的數據。
OSI的七層模型有哪些
物理層、鏈路鏈路層、網絡層、傳輸層、會話層、表示層、應用層
get和post的區別
get對應着數據的獲取,post對應着數據的更改;
get請求會將請求參數加載地址中,而post請求是將數據包含在包體中;
所以post的安全性高於get;且地址欄的長度是有限的,所以get能傳輸的參數是有限的,post可以傳輸的數據是不限制大小的;
如何實現跨域
通過jsonp實現跨域
說一下jsonp的實現原理
jsonp是json+padding,動態創建script標籤,通過script標籤的src屬性可以獲得任何域下的js腳本。
設計模式
說一說你熟悉的設計模式
單例模式:單例模式分爲餓漢式和懶漢式,餓漢式。餓漢式是一開始就對實例進行創建,而懶漢式是在需要的時候纔開始創建;單例模式的實現重點在於將構造方法私有化,在類的內部進行實例的創建,並提供方法給外部獲取。
觀察者模式:對象間一對多的依賴關係,當這一個對象狀態發生改變的時候,所有依賴他的對象都得到通知並被自動更新
裝飾者模式:對已有的業務邏輯進行封裝,使其獲得額外測功能
適配器模式:將兩個不相同的對象聯繫在一起
工廠模式:工廠模式分爲簡單工廠模式、工廠方法模式和抽象方法模式;
簡單工廠模式主要包含一個抽象的接口,一些接口的實現類和一個工廠類,
工廠方法模式主要包含抽象產品、具體產品、抽象工廠、具體工廠,
抽象工廠模式與工廠方法模式的區別是,工廠方法模式的工廠只生產單一的產品,而抽象工廠模式的工廠生產多種產品
- 簡單工廠和抽象工廠的區別
spring/spring mvc
爲什麼要使用spring
spring是在企業級開發中簡化開發工作而存在的,是一個輕量級的ioc和aop的容器框架
解釋一下什麼是aop
aop是面向切面編程,就是在java各類中都會使用到的部分抽離出來形成一個模塊,如日誌、事務、權限等
解釋一下什麼是ioc
ioc是控制反轉,我們以往創建對象使用new的形式來創建,現在將創建對象的權利交給spring容器類實現,需要使用的時候再進行依賴注入
spring有哪些主要的模塊
數據訪問/繼承、web、aop、核心容器、測試
spring中常用的注入方法有
構造器注入、setter注入、基於註解注入
spring中的bean是線程安全的嗎
本身是不具有線程安全的
spring中支持幾種bean作用域
- spring中自動裝配bean的方法有哪些
可以使用autowired註解進行自動裝配
spring的事務實現方式有哪些
使用@Transactional註解
- 首先在application配置中配置事務管理器
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean>
- 在web的配置中開啓對註解的解析
<tx:annocation-driven transaction-manager="transactionManager" proxy-target-class="true"></tx:annocation-driven>
- 在代碼中使用transactional註解
@Transactional(propagation=Propagation.REQUIRED,rollbackFor=RuntimeException.class)
- 說一下spring的事務隔離
說一下spring mvc的運作流程
- 客戶端發起的請求會提交到前端控制器dispatchServlet;
- 前端控制器根據HandlerMapping映射查找對應的Controller
- Controller進行業務邏輯處理,返回ModelAndView
- ModelAndView提交到前端處理器進行解析
- 將解析結果發到瀏覽器去進行顯示
spring mvc有哪些組件
dispatcherServlet中央處理器
controller控制器
handlerMapper映射處理器
@RequestMapping的作用是什麼
進行地址映射,找到對應的handler
@Autowired的作用是什麼
自動裝配
spring boot/spring cloud
- 什麼是spring boot
spring boot是一種簡化框架使用的框架。以往使用spring框架總是需要一個繁瑣的配置文件,而spring boot的主要就是簡化配置。
- 爲什麼要用spring boot
spring boot使編碼、配置、部署、監控都變得簡單許多
- spring boot核心配置文件是什麼
spring boot中的核心配置文件是application和bootstrp;
bootstrap是系統級別的,application是應用級別的
- spring boot配置文件有哪幾種類型,他們有什麼區別
spring boot的配置文件類型有application和yml兩種;
application是以key=值的形式書寫,yml是以key:值的形式編寫。yml會以空格來區分層級,容易因爲馬虎而出錯
- spring boot有哪些方式來實現熱部署
方法一:在springboot插件配置中加入springloaded的依賴,之後使用maven指令來運行
方法二:添加spring-boot-devtools依賴
mybatis
mybatis中的#{}和${}是什麼區別
#是預編譯的,$是字符串的替換
mybatis在處理#的時候先將其用?替換,再用praparedStatement來設置參數;可以防止sql注入
而$是直接進行字符串的替換;
mybatis有幾種分頁方法
方法一:數組分頁:將查詢出來的所有數據放到list中進行截取
方法二:使用sql語句,如limit或rownum的方式,傳入參數
方法三:使用攔截器
方法四: 使用RowBounds
RowBounds是一次性查詢全部結果嗎?爲什麼
不是。雖然他可以一次性查出很多數據,但是在mybatis有一個fetch size的配置,會限制一次最多出查出數據的多少
mybatis邏輯分頁和物理分頁的區別
邏輯分頁是將數據一次查詢出很多,再去進行一個結果集的分頁,在數據量比較小的情況下效率較高;
物理分頁是在查詢的時候就只返回指定頁數的數據,在數據量大的情況下效率較高
mybatis是否支持延遲加載?延遲加載的原理是什麼
mybatis中可以通過配置支持延遲加載
原理是動態代理
說一下mybatis的一級緩存和二級緩存
一級緩存是默認開啓的,作用在一次會話中,查詢的結果緩存起來,下次再有相同的查詢時就直接在緩存中取,提高效率
二級緩存是全局緩存,可用在不同會話之間。
數據庫
數據庫的三範式是什麼
範式是規範的意思。
第一範式是說數據表的列不可再分隔
第二範式是說數據表中的每行數據都有一個唯一的標識,例如設置主鍵
第三範式是說數據表中不能含有其他數據表除了主鍵之外的其他列,例如設置外鍵
一張自增表裏面總共有17條數據,刪除了最後2條,重啓mysql數據庫,又插入一條數據,此時id是幾
18
如何獲取數據庫版本
select version() 可以得到mysql的數據庫版本
說一下ACID是什麼
事務的四個特性:
原子性、一致性、隔離性、持久性
事務
事務是定義的一系列操作的序列,這些操作要麼都執行,要麼都不執行,只要其中任意一個操作失敗了,其他的操作也不能成功。
事務的四個特徵
- 原子性:事務的操作是不可分割的,要麼都執行,要麼都不執行
- 一致性:事務的每項操作的執行結果狀態必須是一致的,要麼都成功,要麼都不成功。若中途失敗了,則前面的成功操作會回滾。
- 隔離性:程序中往往存在多個事務可能處理同樣的數據,爲了保護數據不被破壞,每個事務是隔離的。
- 持久性:事務處理後的結果時持久的,不會因爲系統故障而有所變動
事務併發的問題
- 髒讀:一個事務讀到了另外的事務沒有提交的數據。(讀到了另外這個事務回滾前的數據)
- 不可重複讀:一個事務中兩次讀取同一數據的值不相同。(第二次讀,讀到其他事務提交後的數據)
- 幻讀:一個事務按搜索條件讀取數據,第二次讀取的數據比第一次讀取到的行數多(第二次讀,其他事務插入並提交了符合搜索條件的數據)
事務隔離級別
- 讀未提交:最低級別的的隔離,以上三種情況都不可避免;
- 讀已提交: 可避免髒讀
- 可重複讀:可避免髒讀、不可重複讀
- 串行化:可避免以上三種情況
索引
索引的作用
索引是對數據庫中的某一列或者多列的值進行排序的一種結構,使用索引可快速訪問數據庫中特定的信息
索引底層是什麼數據結構
B+樹。
B+樹
- B+樹中,最大元素一定存在根節點中
- B+樹中,父節點的元素會在子節點中出現
- B+樹中,葉子結點有地址指向(類指針),構成鏈表
B+樹較之B-樹的優點
- 單一節點存儲更多的元素,減少查詢的IO次數
- 所有查詢都是查詢到子節點,查詢性能更穩定
- 所有的葉子結點形成有序鏈表,便於範圍查詢
怎麼驗證mysql的索引是滿足需求的
使用語句
explain select * from table where type = 1
可以查看sql是如何執行的,以此來看是否滿足
char和varchar的區別
char是定長的,varchar是不定長的
float和double的區別
float是4個字節的,而double是8個字節的
mysql的內連接、做連接、右連接的區別
內連接將匹配的關聯數據都顯示出來
左連接是以左表作爲主表,保留左表的數據,顯示右表符合條件的數據
右連接以右表作爲主表,保留右表的數據,顯示左表符合條件的數據
說一下mysql的常用引擎
InnoDB引擎、MyIasm
where、group by、having
- where子句用來篩選from子句中指定的操作所產生的行
- group by子句對where子句的結構進行分組
- having子句用來從分組的結果中篩選行
having和where的區別
- where操作在分組之前,having子句在分組之後
- having中可以包含聚合函數
mysql分頁和oracle分頁
- mysql是使用關鍵字limit來進行分頁的
...limit offset,size
- oracle分頁使用rownum關鍵字取數據的行數,再加where條件語句來限定行數範圍
select * from (select rownum rn,* from (select * from table order by co) where rn <= 15 )t where t.rn >= 5
in和exist的區別
in是先進行子查詢,再用子查詢的結果去和主查詢做笛卡爾積;
exists是loop循環主查詢的數據去和子查詢做條件比對,結果爲true就保留數據,結果爲false就刪除數據;
所以當子表小主表大的就用in,子表大主表小的就用exists
樂觀鎖和悲觀鎖
在數據庫併發情況下,爲了防止出現類似於超賣的情況,一般需要進行加鎖處理。
樂觀鎖認爲一般不會出現併發問題,只有在更新數據的時候才進行加鎖處理;而悲觀鎖認爲總是會出現併發問題,一開始就進行加鎖處理。
悲觀鎖
在mysql中悲觀鎖的用法:
設置取消自動提交
在查詢數據的時候使用:select * from . for update
樂觀鎖
在mysql中樂觀鎖的用法:
- 添加一個字段爲version
- 查詢時,連帶查詢出版本號version
- 當更新數據的時候需要比對版本號,可成功更新時版本號+1
如果有很多用戶同時訪問並修改數據庫中的某個字段值,怎麼保證數據的正確性
可以在代碼層面進行同步,也可以在數據庫加鎖;
代碼同步可以使用synchronized或者lock;
數據庫加鎖可以使用悲觀鎖或者樂觀鎖,悲觀鎖可以通過for update加鎖;樂觀鎖可以通過添加版本字段,通過比較後更改的方式來實現
說一下mysql的行鎖和表鎖
行鎖鎖住的只是一行數據,而表鎖鎖住的是整張表
說一下樂觀鎖和悲觀鎖
樂觀鎖認爲一般情況不會發生併發問題,只有在寫數據的時候纔會加鎖
悲觀鎖認爲總是會發生問題,所以從一開始就加鎖,無論是讀還是寫
mysql的樂觀鎖需要自己去實現,通過添加版本號字段來實現
mysql的悲觀鎖可以通過在查詢後加上for update來實現
數據庫中的事務是怎麼實現的
事務日誌,在日誌中記錄下數據和進行的操作
MVCC,在數據庫表中隱藏有兩個列,一是記錄數據的創建時間,二是記錄數據的過期時間,裏面存儲的是版本號
- mysql問題排查都有哪些手段
使用show processlist命令查看當前所有連接信息
使用explain命令查詢sql語句的執行計劃
開啓慢查詢日誌,查看慢查詢的sql
- 如何做mysql的性能優化
爲搜索字段添加索引
避免使用select *,而是列出具體的字段