接口(interface)和抽象類(abstract class)的區(qū)別是什么?
- 一個(gè)類實(shí)現(xiàn)(implemens)接口時(shí)必須實(shí)現(xiàn)接口的所有的方法
- 接口中的屬性都是被
public static final
修飾的峡迷,只有常量沒有變量 - 一個(gè)類可以實(shí)現(xiàn)多個(gè)接口
- 接口方法默認(rèn)修飾符是
public abstract
紊馏,且不可以使用其他修飾符 - 不能有構(gòu)造方法
- 接口強(qiáng)調(diào)的是功能
作用:降低耦合
- 一個(gè)類繼承(extends)抽象類時(shí)煤痕,如果不實(shí)現(xiàn)所有的抽象方法念逞,該類也必須是抽象類
- 抽象類既可以有變量碾局,也可以有常量
- 一個(gè)類只能繼承一個(gè)抽象類
- 抽象方法可以有
public灵再、protected和default
來修飾 - 可以有構(gòu)造方法肋层、抽象方法和其他方法
- 抽象類強(qiáng)調(diào)的是從屬關(guān)系
作用:把相同的東西提取出來亿笤,即重用
Servlet的生命周期
- Servlet 通過調(diào)用 init () 方法進(jìn)行初始化。
- Servlet 調(diào)用 service() 方法來處理客戶端的請(qǐng)求栋猖。
- Servlet 通過調(diào)用 destroy() 方法終止(結(jié)束)净薛。
- 最后,Servlet 是由 JVM 的垃圾回收器進(jìn)行垃圾回收的蒲拉。
補(bǔ)充:
Servlet 調(diào)用的service() 方法:
- 每一次請(qǐng)求服務(wù)器都會(huì)開啟一個(gè)新的線程并執(zhí)行一次service方法肃拜,service根據(jù)客戶端的請(qǐng)求類型,調(diào)用doGet雌团、doPost等方法燃领。
Servlet初始化
分三種情況:
- loadOnStartup < 0 或者 沒有設(shè)置loadOnStartup
web容器啟動(dòng)的時(shí)候不做實(shí)例化處理,servlet首次被調(diào)用時(shí)做實(shí)例化 - loadOnStartup > 0
web容器啟動(dòng)的時(shí)候做實(shí)例化處理锦援,順序是由小到大猛蔽,正整數(shù)小的先被實(shí)例化 - loadOnStartup = 0
web容器啟動(dòng)的時(shí)候做實(shí)例化處理,相當(dāng)于是最大整數(shù)灵寺,因此web容器啟動(dòng)時(shí)曼库,最后被實(shí)例化
Object類的常見方法總結(jié)
-
protected Object toString()
返回該對(duì)象的字符串表示,如果不重寫是getClass().getName() + '@' + Integer.toHexString(hashCode())
-->com.leyou.Test@506c589e
-
protected Object getClass()
返回此 Object 的運(yùn)行時(shí)類略板。class com.leyou.Test -
protected Object equals(Object object)
指示其他某個(gè)對(duì)象是否與此對(duì)象“相等”毁枯。
注意:當(dāng)此方法被重寫時(shí),通常有必要重寫 hashCode 方法叮称,以維護(hù) hashCode 方法的常規(guī)協(xié)定种玛,該協(xié)定聲明相等對(duì)象必須具有相等的哈希碼。 -
protected int hashCode()
返回該對(duì)象的哈希碼值瓤檐。
如果根據(jù) equals(Object) 方法蒂誉,兩個(gè)對(duì)象是相等的,那么對(duì)這兩個(gè)對(duì)象中的每個(gè)對(duì)象調(diào)用 hashCode 方法都必須生成相同的整數(shù)結(jié)果距帅。 -
public final void wait(long timeout)
在其他線程調(diào)用此對(duì)象的 notify() 方法或 notifyAll() 方法右锨,或者超過指定的時(shí)間量前,導(dǎo)致當(dāng)前線程等待碌秸。 -
void notifyAll()
喚醒在此對(duì)象監(jiān)視器上等待的所有線程绍移。 -
Object clone()
創(chuàng)建并返回此對(duì)象的一個(gè)副本〖サ纾“副本”的準(zhǔn)確含義可能依賴于對(duì)象的類蹂窖。
x.clone() != x
為true
x.clone().getClass() == x.getClass()
為true
x.clone().equals(x)
為true
為什么equals()方法要重寫?
- 判斷兩個(gè)對(duì)象在邏輯上是否相等恩敌,如根據(jù)類的成員變量來判斷兩個(gè)類的實(shí)例是否相等瞬测,而繼承Object中的equals方法只能判斷兩個(gè)引用變量是否是同一個(gè)對(duì)象。這樣我們往往需要重寫equals()方法。
- 我們向一個(gè)沒有重復(fù)對(duì)象的集合中添加元素時(shí)月趟,集合中存放的往往是對(duì)象灯蝴,我們需要先判斷集合中是否存在已知對(duì)象,這樣就必須重寫equals方法孝宗。
equals重寫有什么注意事項(xiàng)穷躁?
equals 方法在非空對(duì)象引用上實(shí)現(xiàn)相等關(guān)系:
- 自反性:對(duì)于任何非空引用值 x,x.equals(x) 都應(yīng)返回 true因妇。
- 對(duì)稱性:對(duì)于任何非空引用值 x 和 y问潭,當(dāng)且僅當(dāng) y.equals(x) 返回 true 時(shí),x.equals(y) 才應(yīng)返回 true婚被。
- 傳遞性:對(duì)于任何非空引用值 x狡忙、y 和 z,如果 x.equals(y) 返回 true址芯,并且 y.equals(z) 返回 true灾茁,那么 x.equals(z) 應(yīng)返回 true。
- 一致性:對(duì)于任何非空引用值 x 和 y是复,多次調(diào)用 x.equals(y) 始終返回 true 或始終返回 false删顶,前提是對(duì)象上 equals 比較中所用的信息沒有被修改竖螃。
- 非空性:對(duì)于任何非空引用值 x淑廊,x.equals(null) 都應(yīng)返回 false。
spring ioc底層用的什么數(shù)據(jù)結(jié)構(gòu)特咆?
- xml配置文件
- dom4j解決xml
- 工廠設(shè)計(jì)模式
- 反射
HashMap
- HashMap的默認(rèn)長(zhǎng)度為16,是為了降低hash碰撞的幾率
- 紅黑樹一直是O(logn)季惩,鏈表查找的時(shí)間復(fù)雜度為O(n)
HashMap的put流程
①.判斷鍵值對(duì)數(shù)組是否為空或?yàn)閚ull,若條件成立則執(zhí)行resize()進(jìn)行擴(kuò)容腻格;
②.根據(jù)鍵值key計(jì)算hash值得到插入的數(shù)組索引画拾,如果索引位置的值為null,直接新建節(jié)點(diǎn)添加菜职,轉(zhuǎn)向⑥青抛,如果不為空,轉(zhuǎn)向③酬核;
③.判斷桶位的首個(gè)元素是否和key一樣蜜另,如果相同直接覆蓋value,否則轉(zhuǎn)向④嫡意,這里的相同指的是hashCode以及equals举瑰;
④.判斷桶位是否為treeNode,即該節(jié)點(diǎn)是否是紅黑樹蔬螟,如果是紅黑樹此迅,則直接在樹中插入鍵值對(duì),否則轉(zhuǎn)向⑤;
⑤.遍歷該桶位的節(jié)點(diǎn)耸序,判斷鏈表長(zhǎng)度是否大于8忍些,大于8的話把鏈表轉(zhuǎn)換為紅黑樹,在紅黑樹中執(zhí)行插入操作佑吝,否則進(jìn)行鏈表的插入操作(這里用的尾插發(fā))坐昙;遍歷過程中若發(fā)現(xiàn)key已經(jīng)存在直接覆蓋value即可;
⑥.插入成功后芋忿,判斷實(shí)際存在的鍵值對(duì)數(shù)量size是否超過閾值炸客,如果超過,進(jìn)行擴(kuò)容戈钢。
- 大約記得是它首先會(huì)看key為不為空痹仙,為空就調(diào)用一個(gè)put空值的函數(shù),不為空的話它就調(diào)用hash()函數(shù)計(jì)算hash值嗎殉了,接著會(huì)先判斷這個(gè)hash值對(duì)應(yīng)的地址空間是否已經(jīng)有值了开仰,如果有的話,它會(huì)把新的存進(jìn)去薪铜,把舊的返回众弓,放在后面形成鏈表,在jdk1.8之后隔箍,當(dāng)鏈表超過8的時(shí)候就變成了紅黑樹了
補(bǔ)充
- HashMap 允許插入鍵為 null 的鍵值對(duì)谓娃。
- 因?yàn)闊o法調(diào)用 null 的 hashCode() 方法,也就無法確定該鍵值對(duì)的桶下標(biāo)蜒滩,只能通過強(qiáng)制指定一個(gè)桶下標(biāo)來存放滨达。HashMap 使用第 0 個(gè)桶存放鍵為 null 的鍵值對(duì)。
hashMap為什么線程不安全俯艰?
比如一個(gè) ArrayList 類捡遍,在添加一個(gè)元素的時(shí)候,它可能會(huì)有兩步來完成:
- 在 Items[Size] 的位置存放此元素竹握;
- 增大 Size 的值画株。
在單線程運(yùn)行的情況下,如果 Size = 0啦辐,添加一個(gè)元素后谓传,此元素在位置 0,而且 Size=1昧甘;
而如果是在多線程情況下良拼,比如有兩個(gè)線程,線程 A 先將元素存放在位置 0充边。但是此時(shí) CPU 調(diào)度線程A暫停庸推,線程 B 得到運(yùn)行的機(jī)會(huì)常侦。線程B也向此 ArrayList 添加元素,因?yàn)榇藭r(shí) Size 仍然等于 0 (注意哦贬媒,我們假設(shè)的是添加一個(gè)元素是要兩個(gè)步驟哦,而線程A僅僅完成了步驟1)际乘,所以線程B也將元素存放在位置0坡倔。然后線程A和線程B都繼續(xù)運(yùn)行,都增加 Size 的值脖含。
那好罪塔,現(xiàn)在我們來看看 ArrayList 的情況,元素實(shí)際上只有一個(gè)养葵,存放在位置 0征堪,而 Size 卻等于 2。這就是“線程不安全”了关拒。
ConcurrentHashMap加的是什么鎖佃蚜?
- ConcurrentHashMap引入了一個(gè)“分段鎖(1.7)”的概念,具體可以理解為把一個(gè)大的Map拆分成N個(gè)小的HashTable着绊,根據(jù)key.hashCode()來決定把key放到哪個(gè)HashTable中谐算。
- 放棄了Segment(分段鎖)臃腫的設(shè)計(jì),采用Node(數(shù)組+鏈表+紅黑樹)+CAS+Synchronize來保證線程安全
ConcurrentHashMap的get()方法是否需要加鎖归露,為什么洲脂?
- 1.8中ConcurrentHashMap的get操作全程不需要加鎖,這也是它比其他并發(fā)集合如hashtable靶擦、用Collections.synchronizedMap()包裝的hashmap;安全效率高的原因之一腮考。
- get操作全程不需要加鎖是因?yàn)镹ode的成員val是用volatile修飾的和數(shù)組用volatile修飾沒有關(guān)系雇毫。
- 數(shù)組用volatile修飾主要是保證在數(shù)組擴(kuò)容的時(shí)候保證可見性玄捕。
常見的異常整理
Java中的異常分為兩大類:
1.Checked Exception(非Runtime Exception)
2.Unchecked Exception(Runtime Exception)
- 算數(shù)異常類:ArithmeticException
- 空指針異常類型:NullPointerException
- 類型強(qiáng)制轉(zhuǎn)換類型:ClassCastException
- 下標(biāo)越界異常:IndexOutOfBoundsExecption
- 數(shù)組下標(biāo)越界異常:ArrayIndexOutOfBoundsException
- 類轉(zhuǎn)換異常:ClassCastException
synchronize關(guān)鍵字的作用
synchronized的作用:
- Synchronized是Java中解決并發(fā)問題的一種最常用最簡(jiǎn)單的方法 ,他可以確保線程互斥的訪問同步代碼
可以用來修飾:
- 通同步方法(實(shí)例方法)棚放,鎖是當(dāng)前實(shí)例對(duì)象 枚粘,進(jìn)入同步代碼前要獲得當(dāng)前實(shí)例的鎖
- 靜態(tài)同步方法,鎖是當(dāng)前類的class對(duì)象 飘蚯,進(jìn)入同步代碼前要獲得當(dāng)前類對(duì)象的鎖
- 同步方法塊馍迄,鎖是括號(hào)里面的對(duì)象,對(duì)給定對(duì)象加鎖局骤,進(jìn)入同步代碼庫前要獲得給定對(duì)象的鎖攀圈。
舉例
- 同一個(gè)對(duì)象在兩個(gè)線程中分別訪問該對(duì)象的兩個(gè)同步方法,會(huì)產(chǎn)生互斥
- 不同對(duì)象在兩個(gè)線程中調(diào)用同一個(gè)同步方法峦甩,不會(huì)產(chǎn)生互斥
- Synchronized修飾靜態(tài)方法赘来,用類直接在兩個(gè)線程中調(diào)用兩個(gè)不同的同步方法现喳,會(huì)產(chǎn)生互斥
HashSet和TreeSet的區(qū)別
實(shí)現(xiàn)方式
- HashSet:HashSet是哈希表實(shí)現(xiàn)的。
- TreeSet:TreeSet是二叉樹實(shí)現(xiàn)的犬辰。
數(shù)據(jù)是否有序
- HashSet:HashSet中的數(shù)據(jù)是無序的嗦篱。
- TreeSet:Treeset中的數(shù)據(jù)是自動(dòng)排好序的。
是否可以放入null值
- HashSet:可以放入null幌缝,但只能放入一個(gè)null灸促。
- TreeSet:不允許放入null值。
Linux常用命令
- cd涵卵。切換項(xiàng)目目錄
- pwd浴栽。用于顯示工作目錄
- ls。列出路徑或當(dāng)前目錄下的所有文件信息
- cat <文件>轿偎。 表示讀取文件內(nèi)容
- rm命令吃度。rm是remove 的縮寫。用于刪除文件或文件夾贴硫,常用參數(shù)-r -f椿每,-r表示刪除目錄,也可以用于刪除文件英遭,-f表示強(qiáng)制刪除间护,不需要確認(rèn)。同樣的挖诸,刪除文件前需保證當(dāng)前用戶對(duì)當(dāng)前路徑有修改的權(quán)限汁尺。
- mkdir命令。用于創(chuàng)建文件夾
- cp命令多律。用于復(fù)制文件或文件夾痴突。
- kill命令。結(jié)束當(dāng)前進(jìn)程
- ifconfig/ipaddr狼荞。查看IP地址
- touch辽装。創(chuàng)建一個(gè)文件
SQL中IN和EXISTS用法的區(qū)別
- in()適合B表比A表數(shù)據(jù)小的情況 (not in會(huì)使索引失效)
select * from A where id in(select id from B)
- exists()適合B表比A表數(shù)據(jù)大的情況
select A.* from A where xx exists(select xx from B where A.id=B.id)
- 當(dāng)A表數(shù)據(jù)與B表數(shù)據(jù)一樣大時(shí),in與exists效率差不多,可任選一個(gè)使用.
線程池
- new SingleThreadExecutor:創(chuàng)建一個(gè)單線程的線程池,保證所有任務(wù)的執(zhí)行順序按照任務(wù)的提交順序執(zhí)行相味。
- new FixedThreadPool:創(chuàng)建一個(gè)固定大小的線程池拾积。調(diào)用execute()方法。每次提交任務(wù)就成撿一個(gè)線程丰涉,直到線程達(dá)到線程吃的最大大小拓巧。
- new CachedThreadPool:創(chuàng)建一個(gè)可緩存的線程池。大小不做限制
- new ScheduledThreadPool:創(chuàng)建一個(gè)大小無限的線程池一死。定時(shí)以及周期性的執(zhí)行任務(wù)的操作肛度。
創(chuàng)建線程的方法
- 繼承Thread類
- 實(shí)現(xiàn)Runnable接口
- 實(shí)現(xiàn)Callable接口
static
使用場(chǎng)景
- 修飾成員變量和成員方法
- 靜態(tài)代碼塊
- 修飾類(只能修飾內(nèi)部類)
話術(shù)
- 被 static 修飾的成員屬于類,不屬于單個(gè)這個(gè)類的某個(gè)對(duì)象投慈,該類中所有對(duì)象共享承耿,可以并且建議通過類名調(diào)用策吠。被static 聲明的成員變量屬于靜態(tài)成員變量,靜態(tài)變量 存放在 Java 內(nèi)存的方法區(qū)瘩绒。且僅有一份猴抹。
- 靜態(tài)代碼塊定義在類中方法外, 靜態(tài)代碼塊在非靜態(tài)代碼塊之前執(zhí)行(靜態(tài)代碼塊—非靜態(tài)代碼塊—構(gòu)造方法)。 該類不管創(chuàng)建多少對(duì)象锁荔,靜態(tài)代碼塊只執(zhí)行一次.
- 通過類名.來調(diào)用
Redis掛了怎么辦蟀给?
- 因?yàn)閞edis它有持久化的特性,所以在購(gòu)物車這個(gè)場(chǎng)景阳堕,用redis其實(shí)已經(jīng)足夠了跋理,退一萬步說,redis掛了恬总,購(gòu)物車它不會(huì)造成特別大的損失前普。(時(shí)間間隔機(jī)制)但是我知道redis它有三種集群模式,主從模式壹堰,哨兵模式拭卿,還有一個(gè)是分片的模式,但是我們這個(gè)商城沒有用到redis集群贱纠。
- 萬一Redis真的掛了峻厚,我們可以設(shè)置本地緩存(ehcache)+限流(hystrix),盡量避免我們的數(shù)據(jù)庫被干掉(起碼能保證我們的服務(wù)還是能正常工作的)谆焊。事發(fā)后:redis持久化惠桃,重啟后自動(dòng)從磁盤上加載數(shù)據(jù),快速恢復(fù)緩存數(shù)據(jù)辖试。
Redis持久化
- RDB
每隔多少秒生成快照存儲(chǔ)到磁盤等介質(zhì)上 - AOF
把所有的寫指令記錄下來辜王,重啟把寫指令再重新執(zhí)行一遍
排查系統(tǒng)遇到的問題
- 事前:流量達(dá)到高峰,加入來了大批量的請(qǐng)求罐孝,做一些限流呐馆、降級(jí)的操作
- 事中:出發(fā)了我們認(rèn)定為Bug的邏輯,可以發(fā)一些郵件或者通知的報(bào)警
- 事后:?jiǎn)栴}產(chǎn)生后去追查錯(cuò)誤日志肾档,cat命令摹恰,錯(cuò)誤日志的排查
事務(wù)運(yùn)用的場(chǎng)景
- 操作多張表的時(shí)候
- 循環(huán)更新辫继、插入
核心在于怒见,某一個(gè)業(yè)務(wù)失敗了是否可以回滾
ArrayList和LinkedList的插入,刪除時(shí)間復(fù)雜度
操作 | ArrayList | LinkedList |
---|---|---|
讀取 get() | 根據(jù)下標(biāo)直接查詢姑宽,時(shí)間復(fù)雜度O(1) | 遍歷獲取遣耍,時(shí)間復(fù)雜度O(n) |
添加 add(E) | 直接尾部添加,時(shí)間復(fù)雜度O(1) | 直接尾部添加炮车,時(shí)間復(fù)雜度O(1) |
指定位置添加 add(index,E) | 后面元素需要逐個(gè)移動(dòng)舵变,時(shí)間復(fù)雜度O(n) | 指針指向操作酣溃,時(shí)間復(fù)雜度O(n) |
刪除 remove(E) | 后面元素需要逐個(gè)移動(dòng),時(shí)間復(fù)雜度O(n) | 直接指針操作纪隙,時(shí)間復(fù)雜度O(1) |
之前用過Nginx嗎? 你們一般都用它做什么赊豌?
- Nginx肯定用過,首先它本身是一款性能很高的Web服務(wù)器绵咱,我們?cè)谔幚硪造o態(tài)資源都會(huì)利用到它碘饼,當(dāng)然也聽說Nginx也可以結(jié)合一些腳本語言處理動(dòng)態(tài)應(yīng)用,不過這方面倒是沒有接觸過悲伶,我們公司一般會(huì)將nginx和Tomcat相結(jié)合來使用艾恼。另外它還有一個(gè)很功能就是充當(dāng)反向帶服務(wù)器,在我們的微服務(wù)中就是利用它來反向代理Zuul網(wǎng)關(guān)麸锉,從而可以實(shí)現(xiàn)zuul的高可用钠绍,而且它自身攜帶負(fù)載均衡,我們也可以通過修改配置文件來實(shí)現(xiàn)自己的配置花沉。
索引(底層存儲(chǔ)結(jié)構(gòu)B+Tree)
索引的分類
- 普通索引:加快查詢
- 唯一索引:加速+唯一(不能為空)
- 主鍵索引:加速+唯一(可以為空)
- 組合索引:多列值組成一個(gè)索引柳爽,專門用于組合索引(左前匹配原則)
- 全文索引:利用分析技術(shù)等多種算法智能分析文本,篩選我們想要的結(jié)果
使用索引的條件:
- 字段的識(shí)別度不低于70%
- 經(jīng)常作為where條件的字段適合創(chuàng)建索引
- 經(jīng)常作為Order by條件的字段適合創(chuàng)建索引
- 經(jīng)常作為表連接的字段適合創(chuàng)建索引
索引失效的條件:
- 使用 != < > not in等關(guān)鍵字
- 使用like碱屁,例如like %xxx%(失效)泻拦,like xxx%(不會(huì)失效)
- 索引字段不能用于進(jìn)行計(jì)算
- 不要在索引字段使用is null、is not null
在SpringCloud 體系你使用的Cookie 有沒有遇到過什么問題
- 確實(shí)遇到過Cookie 丟失的問題忽媒,原因是Zuul內(nèi)部有默認(rèn)的過濾器争拐,會(huì)對(duì)請(qǐng)求和響應(yīng)頭信息進(jìn)行重組,過濾掉敏感的頭信息晦雨,而Cookie默認(rèn)就是敏感信息架曹,所以就給過濾掉啦,怎么解決呢闹瞧,其實(shí)解決很簡(jiǎn)單绑雄,就是覆蓋sensitiveHeaders這個(gè)過濾請(qǐng)求頭的最終屬性的為null就可以啦!需要我們?cè)谂渲梦募信渲?
zuul.sensitive-headers=
volatile 的特性
- 在Java中奥邮,每個(gè)線程都有一個(gè)獨(dú)立的內(nèi)存空間万牺,稱為工作內(nèi)存; 它保存了用于執(zhí)行操作的不同變量的值。在執(zhí)行操作之后洽腺,線程將變量的更新值復(fù)制到主存儲(chǔ)器脚粟,這樣其他線程可以從那里讀取最新值。
簡(jiǎn)單地說蘸朋,volatile關(guān)鍵字標(biāo)記一個(gè)變量核无,在多個(gè)線程訪問它的情況下,總是轉(zhuǎn)到主內(nèi)存藕坯,讀取和寫入团南。 - 保證可見性(強(qiáng)制刷新在主存,其他線程緩存無效)和有序性(禁止指令重排序),這些都是上面的用內(nèi)存屏障完成的噪沙。
- 保證了不同線程對(duì)這個(gè)變量進(jìn)行操作時(shí)的可見性,即一個(gè)線程修改了某個(gè)變量的值吐根,這新值對(duì)其他線程來說是立即可見的正歼。(實(shí)現(xiàn)可見性)
- 禁止進(jìn)行指令重排序。(實(shí)現(xiàn)有序性)
- volatile 只能保證對(duì)單次讀/寫的原子性拷橘。i++ 這種操作不能保證原子性朋腋。
你要悄悄拔尖,然后驚艷所有人膜楷!