Java基礎(chǔ)知識(shí)
1. 基礎(chǔ)
==募疮、equals和hashCode的區(qū)別
1载碌、==:對(duì)于基本類型,比較的是它們的值垫蛆;對(duì)于引用類型壹将,比較的是引用的值嗤攻,也就是對(duì)象實(shí)例的地址
2、equals()
方法是Object類中的方法诽俯,默認(rèn)實(shí)現(xiàn)的是public boolean equals(Object obj) {return (this == obj);}
這說明如果一個(gè)類沒有重寫equals()方法妇菱,它默認(rèn)就使用==操作符,也就是比較兩個(gè)變量指向的對(duì)象是否是同一對(duì)象暴区, 這時(shí)候使用equals和使用==會(huì)得到同樣的結(jié)果
3闯团、hashCode()方法和equals()方法的作用其實(shí)一樣,在Java里都是用來對(duì)比兩個(gè)對(duì)象是否相等一致仙粱。重寫equals()方法一般比較全面比較復(fù)雜房交, 這樣效率比較低,而利用hashCode()方法進(jìn)行對(duì)比伐割,則只要生成一個(gè)hash值進(jìn)行對(duì)比就行了候味。那么hashCode既然效率這么高為什么還有equals呢呢刃唤? 因?yàn)閔ashCode并不是完全可靠,有時(shí)候不同的對(duì)象他們生成的hashCode也會(huì)一樣(hash沖突)白群,所以hashCode只能說是大部分時(shí)候可靠尚胞,并不是絕對(duì)可靠。equals()相等的兩個(gè)對(duì)象他們的hashCode()肯定相等
hashCode()相等的兩個(gè)對(duì)象他們equals()不一樣相等
重載(Overload)和重寫(Override)的區(qū)別
重寫(Override)
重寫發(fā)生在運(yùn)行期,針對(duì)父類和子類來說的帜慢,是在子類中重寫父類的方法
1笼裳、要求方法名,參數(shù)個(gè)數(shù)和類型必須相同
2粱玲、返回的數(shù)據(jù)類型必須與父類相同或者是其子類
3躬柬、訪問修飾符的限制一定要大于父類中該方法的訪問修飾符(public > protected > default > private)
4、重寫方法一定不能拋出新的檢查異吵榧酰或者比被重寫方法申明更加寬泛的檢查型異常
重載(Overload)
重載發(fā)生在編譯期允青,針對(duì)一個(gè)類說的,是JAVA中多態(tài)性的一種表現(xiàn)
1胯甩、要求方法名相同
2昧廷、必須有不同的參數(shù)列表
3、可以有不同的返回類型
4偎箫、可以有不同的修飾符
5木柬、可以拋出不同的異常
StringBuilder、StringBuffer淹办、+眉枕、String.concat
- StringBuilder是線程不安全;
- StringBuffer是線程安全怜森;
- +實(shí)際上內(nèi)部是用的是StringBuilder來實(shí)現(xiàn)的速挑,所以非循環(huán)體可以直接使用+,循環(huán)體不行副硅,因?yàn)闀?huì)頻繁創(chuàng)建StringBuilder姥宝;
- String.concat實(shí)質(zhì)是new String,效率也低
耗時(shí)排序:
StringBuilder < StringBuffer < String.concat < +
2. 容器
List恐疲、Map腊满、Set
- Set(集合) 是無序、不可以重復(fù)的
- List(列表) 是有序培己、可以重復(fù)的
- Map(映射) 是鍵值對(duì):Map<Key, Value>
ArrayList碳蛋、Vector、LinkedList省咨、CopyOnWriteArrayList
ArrayList
非線程安全肃弟,基于數(shù)據(jù)實(shí)現(xiàn),查找快:o(1),增刪慢o(n)
初始容量為10笤受,擴(kuò)展通過System.arrayCopy方法穷缤。LinkedList
非線程安全,基于雙向鏈表實(shí)現(xiàn)箩兽,查找慢o(n)绅项,增刪快o(1)
封裝了隊(duì)列和棧的調(diào)用Vector
方法是同步的,加了synchronized關(guān)鍵字比肄,線程安全的。當(dāng)元素超過它的初始化大小時(shí)囊陡,Vector會(huì)將它的容量翻倍芳绩,而ArrayList只增加50%的大小,這樣ArrayList就有利于節(jié)約內(nèi)存空間撞反。ArrayList與Vector都可以設(shè)置初始化的空間大小妥色,Vector還可以設(shè)置增加的空間大小,而ArrayList沒有提供設(shè)置增長(zhǎng)空間的方法CopyOnWriteArrayList
這是一個(gè)ArrayList的線程安全的變體遏片,其中所有可變操作(add嘹害、set等等)都是通過對(duì)底層數(shù)組進(jìn)行一次新的復(fù)制來實(shí)現(xiàn)的,在CopyOnWriteArrayList里面增加了一個(gè)數(shù)據(jù)吮便,這個(gè)時(shí)候CopyOnWriteArrayList底層實(shí)現(xiàn)添加的原理是先copy出一個(gè)容器(可以簡(jiǎn)稱副本)笔呀,再往新的容器里添加這個(gè)新的數(shù)據(jù),最后把新的容器的引用地址賦值給了之前那個(gè)舊的容器地址髓需,但是在添加這個(gè)數(shù)據(jù)的期間许师,其他線程如果要去讀取數(shù)據(jù),仍然是讀取到舊的容器里的數(shù)據(jù)僚匆。這對(duì)于讀操作遠(yuǎn)遠(yuǎn)多于寫操作的應(yīng)用非常適合微渠。CopyOnWriteArrayList在兼顧了線程安全的同時(shí),又提高了并發(fā)性咧擂,性能比Vector有不少提高(CopyOnWriteArrayList方法中使用了lock鎖逞盆,Vector只是方法上加synchronized)
HashMap、TreeMap松申、LinkedHashMap云芦、HashTable、ConcurrentHashMap
HashMap
非線程安全攻臀,HashMap由數(shù)組+鏈表組成焕数,數(shù)組是HashMap的主體,鏈表則是主要為了解決哈希沖突而存在的刨啸。允許null鍵和null值HashTable
基于哈希表實(shí)現(xiàn)堡赔,特點(diǎn)和 hashMap是一樣的,但是線程安全设联,不允許null鍵或null值TreeMap
基于紅黑樹實(shí)現(xiàn)善已,非線程安全灼捂,不允許null鍵但運(yùn)行null值,存儲(chǔ)在它里面的key是從小到大排好序的换团。由于內(nèi)部要排序悉稠,所以存入的key必須是相同對(duì)象LinkedHashMap
LinkedHashMap也是一個(gè)HashMap,但是內(nèi)部維持了一個(gè)雙向鏈表艘包,可以保持順序ConcurrentHashMap
基于哈希表實(shí)現(xiàn)的猛。線程安全,不允許null鍵或null值想虎。
不同于HashTable實(shí)現(xiàn)線程安全的策略 —— 簡(jiǎn)單粗暴卦尊,get/put所有相關(guān)操作加入synchronized,這就導(dǎo)致所有操作需要競(jìng)爭(zhēng)同一把鎖舌厨;ConcurrentHashMap采用了非常精妙的“分段鎖”策略岂却,其主干是個(gè)Segment數(shù)組。一個(gè)Segment就是一個(gè)子哈希表裙椭,Segment里維護(hù)了一個(gè)HashEntry數(shù)組躏哩,所以,并發(fā)環(huán)境下揉燃,對(duì)于同一個(gè)Segment的操作才需考慮線程同步扫尺,不同的Segment則無需考慮
總結(jié)
當(dāng)你想要強(qiáng)行給插入的元素維護(hù)一個(gè)想要的順序時(shí),應(yīng)該使用TreeMap炊汤;當(dāng)你想要元素順序與插入順序一致時(shí)器联,應(yīng)該使用LinkedHashMap;不考慮線程安全的其它情況應(yīng)該使用HashMap婿崭,因?yàn)樗男阅茏顑?yōu)拨拓;考慮線程安全的話,應(yīng)盡量使用ConcurrentHashMap而不是HashTable氓栈,因?yàn)槠湫蕦?shí)在太過低下渣磷。
HashSet、LinkedHashSet授瘦、TreeSet與Map類似
HashMap和ArrayMap對(duì)比
1. 查找效率
HashMap因?yàn)槠涓鶕?jù)hashCode的值直接算出index醋界,所以其查找效率是隨著數(shù)組長(zhǎng)度增大而增加的。
ArrayMap使用的是二分法查找提完,所以當(dāng)數(shù)組長(zhǎng)度每增加一倍時(shí)形纺,舊需要多進(jìn)行一次判斷,效率下降徒欣。
所以對(duì)于Map數(shù)量比較大的情況下逐样,推薦使用HashMap
2. 擴(kuò)容數(shù)量
HashMap初始值16個(gè)長(zhǎng)度,每次擴(kuò)容的時(shí)候,直接申請(qǐng)雙倍的數(shù)組空間
ArrayMap每次擴(kuò)容的時(shí)候脂新,如果size長(zhǎng)度大于8時(shí)申請(qǐng)size*1.5個(gè)長(zhǎng)度挪捕,大于4小于8時(shí)申請(qǐng)8個(gè),小于4時(shí)申請(qǐng)4個(gè)
這樣比較ArrayMap其實(shí)時(shí)申請(qǐng)了更少的空間争便,但是擴(kuò)容的頻率會(huì)更高级零。因此,如果當(dāng)數(shù)量比較大的時(shí)候滞乙,還是使用HashMap更合適奏纪,因?yàn)槠鋽U(kuò)容的次數(shù)要比ArrayMap少很多。
3. 查找效率
HashMap每次擴(kuò)容的時(shí)候時(shí)重新計(jì)算每個(gè)數(shù)組成員的位置斩启,然后放到新的位置亥贸。
ArrayMap則是直接使用System.arraycopy。
所以效率上肯定是ArrayMap更占優(yōu)勢(shì)浇垦。
4. 內(nèi)存耗費(fèi)
以ArrayMap采用了一種獨(dú)特的方式,能夠重復(fù)的利用因?yàn)閿?shù)據(jù)擴(kuò)容而遺留下來的數(shù)組空間荣挨,方便下一個(gè)ArrayMap的使用男韧。而HashMap沒有這種設(shè)計(jì)。
由于ArrayMap只緩存了長(zhǎng)度是4和8的時(shí)候默垄,所以如果頻繁的使用到Map此虑,而且數(shù)據(jù)量都比較小的時(shí)候,ArrayMap無疑是相當(dāng)?shù)墓?jié)省內(nèi)存的口锭。總結(jié)
數(shù)據(jù)量比較小(1000內(nèi))朦前,并且需要頻繁的使用Map存儲(chǔ)數(shù)據(jù)的時(shí)候,推薦使用ArrayMap鹃操。 而數(shù)據(jù)量比較大的時(shí)候韭寸,則推薦使用HashMap。
ArrayMap荆隘、SparseArray
ArrayMap
- 基于兩個(gè)數(shù)組實(shí)現(xiàn)恩伺,一個(gè)存放 hash;一個(gè)存放鍵值對(duì)椰拒。擴(kuò)容的時(shí)候只需要數(shù)組拷貝晶渠,不需要重建哈希表
- 內(nèi)存利用率高
- 不適合存大量數(shù)據(jù),因?yàn)闀?huì)對(duì) key 進(jìn)行二分法查找(1000以下)
SparseArray
- 基于兩個(gè)數(shù)組實(shí)現(xiàn)燃观,int 做 key褒脯,避免了對(duì)key的自動(dòng)裝箱(int轉(zhuǎn)為Integer類型)
- 內(nèi)存利用率高
- 不適合存大量數(shù)據(jù),因?yàn)闀?huì)對(duì) key 進(jìn)行二分法查找(1000以下)
總結(jié)
SparseArray和ArrayMap都差不多缆毁,假設(shè)數(shù)據(jù)量在1000以內(nèi):
- 如果key的類型已經(jīng)確定為int類型番川,那么使用SparseArray,因?yàn)樗苊饬俗詣?dòng)裝箱的過程,如果key為long類型爽彤,它還提供了一個(gè)LongSparseArray來確保key為long類型時(shí)的使用
- 如果key類型為其它的類型养盗,則使用ArrayMap
3. 網(wǎng)絡(luò)
網(wǎng)絡(luò)協(xié)議模型
應(yīng)用層: 負(fù)責(zé)處理特定的應(yīng)用程序細(xì)節(jié)(HTTP、FTP适篙、DNS)
傳輸層: 為兩臺(tái)主機(jī)提供端到端的基礎(chǔ)通信(TCP往核、UDP)
網(wǎng)絡(luò)層: 控制分組傳輸、路由選擇等(IP)
鏈路層: 操作系統(tǒng)設(shè)備驅(qū)動(dòng)程序嚷节、網(wǎng)卡相關(guān)接口
TCP聂儒、UDP區(qū)別
TCP連接,可靠硫痰,有序衩婚,面向字節(jié)流,速度慢
UDP無連接效斑,不可靠非春,無序,面向報(bào)文缓屠,速度快
TCP三次握手奇昙、四次揮手
TCP三次握手
1、A:你能聽到嗎敌完?
2储耐、B:我能聽到,你能聽到嗎滨溉?
3什湘、A:我能聽到,開始吧
A和B兩方都要能確保:我說的話晦攒,你能聽到闽撤;你說的話,我能聽到脯颜。所以需要三次握手
TCP四次揮手
1腹尖、A:我說完了
2、B:我知道了伐脖,等一下热幔,我可能還沒有說完
3、B:我也說完了
4讼庇、A:我知道了绎巨,結(jié)束吧
B收到A結(jié)束的消息后B可能還沒有說完,沒法立即回復(fù)結(jié)束標(biāo)識(shí)蠕啄,只能等說完再告訴A我說完了
4. 線程
并發(fā)編程的3個(gè)基本概念
原子性(即一個(gè)操作或者多個(gè)操作 要么全部執(zhí)行并且執(zhí)行的過程不會(huì)被任何因素打斷场勤,要么就都不執(zhí)行戈锻。)
可見性(指當(dāng)多個(gè)線程訪問同一個(gè)變量時(shí),一個(gè)線程修改了這個(gè)變量的值和媳,其他線程能夠立即看得到修改的值格遭。)
有序性(即程序執(zhí)行的順序按照代碼的先后順序執(zhí)行。)
volatile 關(guān)鍵字
只能用來修飾變量留瞳,適用修飾可能被多線程同時(shí)訪問的變量
相當(dāng)于輕量級(jí)的 synchronized拒迅,volatitle 能保證有序性(禁用指令重排序)、可見性她倘;后者還能保證原子性
變量位于主內(nèi)存中璧微,每個(gè)線程還有自己的工作內(nèi)存,變量在自己線程的工作內(nèi)存中有份拷貝硬梁,線程直接操作的是這個(gè)拷貝
被 volatile 修飾的變量改變后會(huì)立即同步到主內(nèi)存前硫,保持變量的可見性.
單例模式,為什么需要volatile
volatile想要解決的問題是荧止,在另一個(gè)線程中想要使用instance屹电,發(fā)現(xiàn)instance!=null,但是實(shí)際上instance還未初始化完畢這個(gè)問題
instance = new Instance();
可以分解為3行偽代碼
- 分配內(nèi)存
- 初始化對(duì)象
- 設(shè)置instance指向剛分配的地址
上面的代碼在編譯器運(yùn)行時(shí)跃巡,可能會(huì)出現(xiàn)重排序 從1-2-3 排序?yàn)?-3-2線程A在執(zhí)行
instance = new Instance();
代碼時(shí)危号,B線程進(jìn)來,而此時(shí)A執(zhí)行了 1和3瓷炮,沒有執(zhí)行2,此時(shí)B線程判斷instance不為null 直接返回一個(gè)未初始化的對(duì)象递宅,就會(huì)出現(xiàn)問題
lock 和 synchronized
synchronized 是 Java 關(guān)鍵字娘香,內(nèi)置特性;Lock 是一個(gè)接口
synchronized 會(huì)自動(dòng)釋放鎖办龄;lock 需要手動(dòng)釋放烘绽,所以需要寫到 try catch 塊中并在 finally 中釋放鎖
synchronized 無法中斷等待鎖;lock 可以中斷
Lock 可以提高多個(gè)線程進(jìn)行讀/寫操作的效率
競(jìng)爭(zhēng)資源激烈時(shí)俐填,lock 的性能會(huì)明顯的優(yōu)于 synchronized
wait 和 sleep
sleep 是 Thread 的靜態(tài)方法安接,可以在任何地方調(diào)用
wait 是 Object 的成員方法,只能在 synchronized 代碼塊中調(diào)用英融,否則會(huì)報(bào) IllegalMonitorStateException 非法監(jiān)控狀態(tài)異常
sleep 不會(huì)釋放共享資源鎖盏檐,wait 會(huì)釋放共享資源鎖
四種引用
強(qiáng)引用: 不會(huì)被回收
軟引用: 內(nèi)存不足時(shí)會(huì)被回收
弱引用: gc 時(shí)會(huì)被回收
虛引用: 無法通過虛引用得到對(duì)象,可以監(jiān)聽對(duì)象的回收