為什么java只有值傳遞?
- 按值呼叫,表示方法接收的是呼叫者的值
- 按參考呼叫,表示方法接收的是呼叫者提供的變數地址
一個方法可以修改傳遞參考所對應的變數值,而不能修改傳遞值呼叫所對應的變數值
java采用按值傳遞,也就是說,方法得到的是所有引數值的一個拷貝,也就是說,方法不能修改傳遞給它任何引數變數的內容,
ArrayList
ArrayList,他的底層結構是陣列,在初始化的時候,資料量為零,當你add的時候,它會默認變為10,擴容機制是每次擴容為之前的1.5倍,他的特性是查詢比較快,洗掉效率比較低,
首先它是有序的,可重復的資料,作為List介面的主要實作者,
執行緒不安全,效率高,底層資料結構是陣列,在jdk1.7的情況下,在new的時候,底層會創建一個長度為10的陣列,但在1.8的時候,new的時候并不會創建陣列,而是在第一次呼叫add的時候,底層才創建了一個長度為10的陣列,也就是說在jdk1.7執行緒不安全,效率高,底層資料結構是陣列,在jdk1.7的情況下,在new的時候,底層創建的是一個長度為10的Object陣列,但在jdk1.8的時候,new的時候并不創建陣列,而是在第一次呼叫add的時候,底層才創建了一個長度為10的陣列,也就是說在jdk1.7的ArrayList的物件的創建類似于單例的餓漢式,在jdk1.8,ArrayList物件的創建類似于單例的懶漢式,延遲了陣列的創建,節省記憶體
在擴容方面,是原來的1.5倍,同時將原來的陣列中的資料復制到新的陣列中,
LinkedList
LinkedList底層結構是一個帶有頭結點和尾結點的雙向鏈表,他提供了兩種插入方式,一個是頭插LikedFirst,還有一個是尾插LikedLast,他的特性非常適合增加 洗掉的場景,他的查詢在量大的時候比較慢
LinkedList為什么查詢慢呢
他在查詢的時候,因為是鏈表查詢,從第一個開始一個一個的去比較
ArrayList 查詢的時候就會很快嗎
它是根據角標查詢的,所以會很快,
對于頻繁的插入和洗掉操作,效率比ArrayList高,底層使用雙向鏈表存盤,
Vector
他跟ArrayList一樣底層都是一個陣列,它又有一點區別,它其中大部分的方法都被Synchronized關鍵字所修飾,所以說它是一個執行緒安全的,他擴容的時候與ArrayList還是有點區別的,他的擴容的大小是以兩倍擴容,
HashMap
HashMap首先從他的底層結構來說,在1.7和1.8的時候是不一樣的,在1.7的時候,底層資料結構是一個長度是16的陣列和一個單鏈表,到了1.8的時候,改成了陣列加上一個單鏈表或者紅黑樹的一個方式,在單鏈表和紅黑樹之間轉換,它的單鏈表的長度大于等于8,并且它的Hash桶大于等于64的時候,它會將單鏈表轉換為紅黑樹的形式存盤,要是紅黑樹的結點的數量小于或等于6的時候,它會重新再轉成一個單鏈表,這是它底層結構的一個變化,另外一個關于它的hash桶的數量,它的默認是16個,有一個默認的閾值,閾值默認是0.75,這關系到它的擴容
擴容它是首先檢查陣列里元素的個數,因為有一個loadFactor(負載因子)默認值是0.75,哈希桶默認是16,他的閾值是16*0.75=12,當它哈希桶占用的容量大于12的時候,就會觸發一個擴容,他擴容成之前哈希桶容量的兩倍,并將原來的資料復制過來
LinkedHashMap
底層使用的結構與HashMap相同,因為LinedHashMap繼承與HashMap,他們的區別在于LinedHashMap內部提供了Entry,替換HashMap中的Node,能夠記錄添加元素的先后順序,
TreeMap
向TreeMap中添加key-value,要求key必須是由一個類創建的物件
因為要安裝key進行排序:自然排序,定制排序
HashSet
添加程序:
- 呼叫HashCode,計算哈希值,根據某種演算法求出索引的位置
- 如果該位置沒有其他元素,就添加成功
- 有元素,但hash值不相同,添加成功
- 有元素,Hash值相同,但equal不相同,添加成功
- 有元素,Hash值相同且equal元素也相同,添加失敗
對于添加成功的情況2和情況3而言:元素a 與已經存在指定索引位置上資料以鏈表的方式存盤,
jdk 7:元素a放到陣列中,指向原來的元素,
jdk 8:原來的元素在陣列中,指向元素a
LinkedHashMap
LinkedHashSet是HashSet的子類,在添加資料的同時,每個資料還維護了兩個參考,記錄此資料前一個資料和后一個資料
優點:對于頻繁的遍歷操作,LinedHashSet效率高于HashSet
Array和ArrayList的不同點
- Array可以包含基本型別和物件型別,ArrayList只能包含物件型別
- Array大小是固定的,ArrayList的大小是動態變化的
TreeSet
向TreeSet中添加的資料,要求是相同類的物件
- 兩種排列順序,自然排序(實作Comparable介面)和定制排序(Comparatot)
- 自然排序中,比較兩個物件是否相同的標準為:compareTo()回傳0.不再是equals().
- 定制排序中,比較兩個物件是否相同的標準為:compare()回傳0.不再是equals().
ConcurrentHashMap
ConcurrentHashMap具有鎖分段的技術,使用起來比HashMap和HashTable要優良,
Hashmap是執行緒不安全的,所以一般在并發環境下不建議使用;而HashTable雖然是執行緒安全的,但是由于使用了同步鎖,在并發環境下效率低下,因為所有訪問HashTable的執行緒都必須競爭同一把鎖,假如容器中有多把鎖,每把鎖用于用于鎖容器其中一部分的資料,那么當執行緒訪問容器里不同資料段的資料時,執行緒間就不會存在鎖競爭,從而可以有效的提高并發效率,這就是ConcurrentHashMap鎖所使用的鎖分段技術,
Map和ConcurrentHashMap的區別
- Map是執行緒不安全的,put在多執行緒情況下,會形成環從而導致死回圈
- ConcurrentHashMap是執行緒安全的,采用分段鎖機制,減少鎖的粒度
Synchronized
- Synchronized修飾的靜態方法以及同步代碼塊鎖的是類,執行緒想要執行對應同步代碼,需要獲得類鎖
- Synchronized修飾成員方法,執行緒獲取的是當前呼叫該方法的物件實體的物件鎖
volatile
- 可見性:可以使得一個執行緒修改后的變數立即對其他執行緒可見
- 不保證原子性
- 禁止指令重排
sychronized和lock
sychronized是java的關鍵字,當它用來修飾一個方法或一個代碼塊的時候,能夠保證在同一時刻最多只有一個執行緒執行該段,jdk1.5之后引入了自旋鎖,鎖粗化,輕量級鎖,偏向鎖來有優化關鍵字的性能,
Lock是一個介面,而synchronized是java中的關鍵字,sychronized在發生例外時,會自動釋放執行緒占有的鎖,因此不會導致死鎖現象的發生,而Lock在發生例外時,如果沒有主動unLock()釋放鎖,則很有可能導致死鎖的現象,因此使用Lock時需要在finally塊中釋放鎖,Lock可以讓等待鎖的執行緒回應中斷,而synchroniezd卻不行,使用synchrnized時,等待的執行緒會一直等待下去,不能夠回應中斷,通過Lock可以知道沒有成功獲取鎖,而synchronized卻無法辦到,
final
- final修飾一個類時,表示該類無法被繼承
- final修飾一個方法時,表示該方法不可被覆寫
- final修飾一個屬性時,表示該屬性一旦被初始化便不可更改
static
- static表示一個成員變數或者成員方法可以在沒有所屬類的實體變數的情況下能被訪問
- java中的static方法不能被覆寫,因為方法覆寫是基于運行時動態系結的,而static方法是編譯時靜態系結的,static方法跟類的任何實體都不相關
StringBuffer和StringBuilder
- StringBuffer是執行緒安全的,StringBuildr是執行緒不安全的,底層實作上的話,StringBuffer其實就是比StringBuilder多了一個Synchronized修飾符
介面和抽象類的區別
不同點:
- 介面中所有的方法隱含都是抽象的,而抽象類中則可以同時包含抽象和非抽象的方法
- 類可以實作多個介面,但是只能繼承一個抽象類
- java介面中宣告的變數都是final的,而抽象類可以包含非final的變數
- 介面的成員函式默認都是public的,抽象類的成員函式可以是private,protected或者是public
- 介面是絕對抽象的,不可以被實體化,抽象類也不可以被實體化,但是如果它包含main方法的話是可以被呼叫的
Comparable和Comparator
- 自然排序:使用Comparable介面重寫compareTo(obj)方法
- 定制排序:使用Comparator介面重寫compare(Object o1,Object o2)方法
反射
反射機制是指,在運行狀態中,對于任意一個類,可以知道它的任意屬性和方法,對于任意一個物件,都能夠呼叫它的任意方法和屬性,對于這種動態呼叫物件方法的功能成為java語言的反射機制
反射創建物件
- 通過類物件呼叫newInstance()方法
- getConstructor()或者getDeclaredConstructor()方法獲得構造器并呼叫其newInstance()方法創建物件,
獲取和設定物件的私有欄位的值
通過類物件getDeclaredField()方法,再通過setAccessible(true)將其設定為可以訪問,接下來通過get/set方法類獲取/設定欄位的值了
行程和執行緒的區別
- 行程是資源分配的最小單位,執行緒是cpu調度的最小單位
start和run的區別
- start方法會創建一個新的子執行緒并啟動
- run()方法只是Thread的一個普通方法的呼叫(還是在主執行緒里執行)
Thread和Runnable的去唄
- Thread是一個類,Runnable是一個介面,Thread類實作了Runnable介面
- Thread是實作了Runnable介面的類,通過start給Runnable的run方法賦上多執行緒的特性,因為java是單一繼承原則,為了提升系統的可擴展性,推薦通過使業務類實作Runnable介面將業務邏輯封裝在run方法里
執行緒的狀態
- 新建
- 運行
- 限期等待
- 無限期等待
- 阻塞
- 結束
sleep和wait的區別
sleep()方法是Thread類方法,wait方法是Object類中定義的方法
sleep可以在任何地方使用
wait方法只能在sychronized方法或者synchronized塊中使用
最本質的差別
sleep方法只會讓出cpu,不會導致鎖的變化,如果當前執行緒是擁有鎖的,那么Thread.sleep方法不會讓執行緒釋放鎖,而只會主動讓出cpu,讓出cpu,cpu就可以去執行其他任務了
wait方法不僅會讓出cpu,而且還會釋放以及占有的同步資源鎖,以便它在等待該資源的執行緒得到該資源進而去執行
notify和notifyAll的區別
- notifyAll會讓所有處于等待池中的執行緒全部進入鎖池去競爭獲取鎖的機會,沒有獲取到鎖的只能等待其他機會去獲取鎖,不能主動回到執行緒池中,
- notify 只能隨機選取一個處于等待池中的執行緒去競爭獲取鎖的機會
yield函式
- 當呼叫Thread.yield()方法時,會給執行緒調度器一個當前執行緒愿意讓出CPU使用的暗示,但是執行緒調度器會忽略這個暗示,
- yield方法對鎖的行為不會有影響的,不會讓當前執行緒讓出鎖
interrupt
呼叫interrupt方法,通知執行緒應該中斷了,該執行緒到底是中斷還是繼續執行,應該由這個執行緒自己去處理
如果執行緒處于被阻塞狀態,例如:sleep,wait,join狀態,那么執行緒將立即退出被阻塞狀態,并拋出一個InterruptedException例外
如果執行緒處于正常活動狀態,那么會將該執行緒的中斷標識設定為true,被設定中斷標示的執行緒將繼續正常運行,不受影響
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/140450.html
標籤:Java
上一篇:集合類Map底層資料結構總結
