- Java語言的特性
Java的三大特性:封裝、繼承、多態(tài)
封裝:隱藏對象的屬性和實現(xiàn)細節(jié),僅對外提供公共的訪問方式。好處:提高重用性和安全性。
繼承:從已有的類中派生出新的類,新的類能吸收已有類的數(shù)據(jù)屬性和行為,平能擴展新的能力。好處:提高代碼的重用性。
多態(tài):同一操作作用于不同的對象,可以有不同的解釋,產(chǎn)生不同的執(zhí)行結(jié)果,就是多態(tài),簡單點說:就是用父類的引用指向子類的對象。
表現(xiàn)形式:方法重寫,方法重載,接口和接口的繼承,類和類的繼承
方法重載:同一個類中,有多個方法名相同,但參數(shù)列表不同
方法重寫:子類重寫父類的方法
好處:當父類中的方法,無法滿足子類的需求時,子類可以對父類的方法進行擴展。
- Java的基本數(shù)據(jù)類型
| 類型 | 字節(jié)大小 | 長度 |
|---|---|---|
| byte | 1 | -128-127 |
| char | 2 | 0-65535 |
| short | 2 | -215-215-1 |
| int | 4 | -231-231-1 |
| long | 8 | -263-263-1 |
| float | 4 | -2128-2128 |
| double | 8 | -21024-21024 |
| boolean | 1/8 | true、false |
- String和StringBuffer、StringBuilder的區(qū)別
- String:用final修飾的char[]數(shù)組,不可變;
- StringBuffer:synchronized修飾方法,線程安全,通過System.copyArray()方法動態(tài)修改;
- StringBuild:線程不安全;
- Java類的加載順序
- 首先加載父類的靜態(tài)字段或者靜態(tài)語句塊;
- 子類的靜態(tài)字段或者靜態(tài)語句塊
- 父類的普通變量以及語句塊
- 父類的構(gòu)造方法被加載
- 子類的變量或者語句塊被加載
- 子類的構(gòu)造方法被加載
- Java類加載的過程
加載-驗證-準備-解析-初始化-使用-卸載
驗證-準備-解析 也被稱為連接階段
-
加載:把代碼數(shù)據(jù)加載到內(nèi)存中,即JVM將字節(jié)碼從各個位置(網(wǎng)絡(luò)、磁盤等)轉(zhuǎn)化為二進制字節(jié)流加載到內(nèi)存中,接著會為這個類在JVM的方法區(qū)創(chuàng)建一個對應的class對象,這個class對象就是這個類各種數(shù)據(jù)的訪問入口。
- 驗證:虛擬機對代碼數(shù)據(jù)進行效驗,查看是否按照JVM規(guī)范編寫。
JVM規(guī)范效驗:JVM會對字節(jié)流進行文件格式效驗,判斷其是否符合;
JVM規(guī)范:是否能被當前版本的虛擬機處理;
代碼邏輯效驗:JVM會對代碼組成的數(shù)據(jù)流和控制流進行效驗,確保JVM運行該字節(jié)碼文件后不會出現(xiàn)致命錯誤; -
準備:JVM開始為類變量分配內(nèi)存并初始化。
內(nèi)存分配的對象:Java中的變量有【類變量】和【類成員變量】兩者類型,類變量指的是被static修飾的變量,而其他所有類型的變量都屬于類成員變量。
在準備階段,JVM只會為類變量分配內(nèi)存,而不會為類成員變量分配內(nèi)存。
類成員變量的內(nèi)存分配需要等到初始化階段才開始。
初始化的類型:在準備階段,JVM會為類成員變量分配內(nèi)存,并為其初始化。但是這里的初始化指的是為變量賦予,Java語言中該數(shù)據(jù)類型的零值,而不是用戶代碼里初始化的值。 -
解析:JVM針對類或接口、字段、類方法、接口方法、方法類型、方法句柄和調(diào)用點限定符7類引用進行解析。
這個階段的主要任務(wù)是將其在常量池中的符號引用替換成直接其在內(nèi)存中直接引用。 - 初始化:JVM會根據(jù)語句執(zhí)行順序?qū)︻悓ο筮M行初始化。
- 使用:當JVM完成初始化階段之后,JVM便開始從入口方法開始執(zhí)行用戶的程序代碼。
- 卸載:當用戶程序代碼執(zhí)行完畢后,JVM便開始銷毀創(chuàng)建的class對象,最后負責運行的JVM也退出內(nèi)存。
- Java類加載器
- Bootstrap ClassLoader:最頂層的加載類,主要加載核心類庫,也就是環(huán)境變量下面%JRE_HOME/lib下的rt.jar、resource.jar、charsets.jar和class等。還可以通過啟動jvm時指定位置;
-
Extention ClassLoader:擴展的類加載器,加載目錄%JRE_HOME/lib/ext目錄下的jar包和class文件。
還可以加載-Djava.ext.dirs選項指定的目錄; - Appclass Loader:也稱為SystemAppClass,加載當前應用的classpath的所有類;
- Custom ClassLoader:自定義加載類;
- Java雙親委派機制
定義:當某個類加載器需要加載某個.class文件時,它首先把這個任務(wù)委托給他的上級類加載器,遞歸這個操作,如果上級的類加載器沒有加載,自己才會去加載這個類。
作用:
- 防止重復加載同一個.class。通過委托去向上問一問,加載過了,就不用再加載一遍了,保證數(shù)據(jù)安全。
- 保證核心.class不能被篡改。透過委托方式,不會去篡改核心.class,及時篡改了也不會去加載,即使加載了也不會是同一個.class對象了。不同的類加載器加載同一個.class也不是同一個Class對象,這樣保證了Class執(zhí)行安全。
- Java反射機制(http://www.itdecent.cn/p/9be58ee20dee)
定義:在運行狀態(tài)中,對于任意一個類,都能夠知道這個類的所有屬性和方法;對于任意一個對象,都能夠調(diào)用它的任意方法和屬性;這種動態(tài)獲取信息以及動態(tài)調(diào)用對象方法的功能稱為java的反射機制。
反射機制的相關(guān)類:
- CLass類:代表類的實體,在運行的Java應用程序中表示類和接口
- Field類:代表類的成員變量(成員變量也稱為類的屬性)
- Method類:代表類的方法
- Constructor:代表類的構(gòu)造方法
- Java的內(nèi)存模型(http://www.itdecent.cn/p/0ecf020614cb)
包括程序計數(shù)器、 虛擬機棧、本地方法棧、方法區(qū)、堆
- 程序計數(shù)器:主要功能是記錄當前線程執(zhí)行程序的位置,通過改變計算數(shù)值來確定執(zhí)行下一條指令。每個線程的創(chuàng)建,都會創(chuàng)建一個程序計數(shù)器,并且對于每個線程而言都是相互獨立的。
- 虛擬機棧:主要功能是臨時存儲線程執(zhí)行到的每個方法需要的參數(shù),其內(nèi)存空間在編譯時就已確定。每創(chuàng)建一個線程,則創(chuàng)建一個虛擬機棧。線程每執(zhí)行到一個方法,對應的棧里就會創(chuàng)建一個棧幀,棧幀會存儲局部變量表、動態(tài)鏈接、操作數(shù)棧和方法出口等信息,執(zhí)行方法,棧幀入棧,方法執(zhí)行完,棧幀出棧。
- 本地方法棧:和Java虛擬機棧一樣,只是記錄native方法執(zhí)行。
- 堆:堆內(nèi)存是存放所有對象實例,也是jvm的GC主要對象。
- 方法區(qū):主要存儲虛擬機棧加載類信息、常量、靜態(tài)變量。
- Java的特性
- 原子性:指一個操作或多個操作要么全部執(zhí)行,且執(zhí)行的過程不會被任何因素打斷,要么就都不執(zhí)行;(處理器會自動保證基本的內(nèi)存操作是原子性的;使用線程鎖保證原子性;使用緩存鎖保證原子性 eg:CAS)。
- 可見性:指當一個線程修改了線程共享變量的值,其他線程能夠立即得知這個修改(比如使用volatile)。
-
有序性:即程序執(zhí)行的順序按照代碼的先后順序執(zhí)行;
(Java內(nèi)存模型中的程序天然有序性可以總結(jié)為一句話:如果在本線程內(nèi)觀察,所有操作都是有序的;如果在一個線程中觀察另一個線程,所有操作都是無序的。不過可以通過synchronized禁止指令重排)
一、引用計數(shù)法:給每個對象添加一個計數(shù)器,當有地方引用該對象時計數(shù)器加1,當引用失效時計數(shù)器減1,用對象計數(shù)器是否為0來判斷對象是否可被回收。
缺點:無法解決循環(huán)引用的問題。
二、可達性分析算法:通過GC ROOT的對象作為搜索起始點,通過引用向下搜索,所走過的路徑稱為引用鏈。通過對象是否有到達引用鏈的路徑來判斷對象是否可被回收。
可作為GC ROOT對象:虛擬機棧中引用的對象、方法區(qū)中類靜態(tài)屬性引用的對象,方法區(qū)中常量引用的對象、本地方法棧中JNI引用的對象。
- 垃圾回收算法
一、標記-清除算法:最基礎(chǔ)的一種垃圾回收算法,它分為兩部分,先把內(nèi)存區(qū)域中的這些對象進行標記,哪些屬于可回收標記出來,然后把這些垃圾領(lǐng)出來清理掉。
缺點:會造成內(nèi)存碎片,需要開辟大內(nèi)存空間時,因為是不連續(xù)的,導致用不了而浪費。
二、復制算法:在標記清楚算法基礎(chǔ)上演化而來,解決標記清除算法的內(nèi)存碎片問題。將可用內(nèi)存按容量劃分為大小相等的兩塊,每次只使用其中一塊。當這一塊的內(nèi)存用完了,就將還存活的對象復制到另外一塊上面,然后再把已使用過的內(nèi)存空間一次性清理掉。保證了內(nèi)存連續(xù)可用,內(nèi)存分配時也就不用考慮內(nèi)存碎片等復雜情況。
缺點:只能使用一半內(nèi)存
三、標記-整理算法:標記-整理算法標記過程仍然與標記-清楚算法一樣,但后續(xù)步驟不是直接對可回收對象進行清理,而是讓所有存活的對象都向一端移動,而清理掉端邊界以外的內(nèi)存區(qū)域。
標記-整理算法解決了內(nèi)存碎片問題,也規(guī)避了復制算法只能利用一半內(nèi)存區(qū)域的弊端。標記-整理算法對內(nèi)存變動更頻繁,需要整理所有的存活對象的引用地址,在效率上比復制算法要差很多。
四、分代收集算法:分代收集算法嚴格來說并不是一種思想或理論,而是融合上述3種基礎(chǔ)的算法思想,而產(chǎn)生的針對不同情況所采用不同算法的一套組合拳,根據(jù)對象存活周期的不同將內(nèi)存劃分為幾塊。
在新生代中,每次垃圾收集時都發(fā)現(xiàn)有大批對象死去,只有少量存活,那就選用復制算法,只需要付出少量存活對象的復制成本就可以完成收集。
在老年代中,因為對象存活率高、沒有額外空間對它進行分配擔保,就必須使用標記-清理算法-或者標記-整理算法來進行回收。
- Java多線程
繼承Thread類、實現(xiàn)Runable接口、線程池創(chuàng)建多線程、實現(xiàn)Callable接口
- Java線程池
- corePoolSize:核心線程池大小
- maximumPoolSize:線程池最大大小
- keepAliveTime:線程存活保持時間
- timeUnit:時間單位
- workQueue:任務(wù)隊列
- threadFactory:線程工廠
- handler:線程飽和策略
- Java 常用線程池
-
newFixedThreadPool
固定線程池,核心線程數(shù)和最大線程數(shù)固定相等,而空閑存活時間為0毫秒,說明此參數(shù)也無意義,工作隊列為最大為Integer.MAX_VALUE大小的阻塞隊列。當執(zhí)行任務(wù)時,如果線程都很忙,就會丟到工作隊列等有空閑線程時再執(zhí)行,隊列滿就執(zhí)行默認的拒絕策略。 -
newCachedThreadPool
帶緩沖線程池,從構(gòu)造看核心線程數(shù)為0,最大線程數(shù)為Integer最大值大小,超過0個的空閑線程在60秒后銷毀,SynchronousQueue這是一個直接提交的隊列,意味著每個新任務(wù)都會有線程來執(zhí)行,如果線程池有可用線程則執(zhí)行任務(wù),沒有的話就創(chuàng)建一個來執(zhí)行,線程池中的線程數(shù)不確定,一般建議執(zhí)行速度較快較小的線程,不然這個最大線程池邊界過大容易造成內(nèi)存溢出。 -
newSingleThreadExecutor
單線程線程池,核心線程數(shù)和最大線程數(shù)均為1,空閑線程存活0毫秒同樣無意思,意味著每次只執(zhí)行一個線程,多余的先存儲到工作隊列,一個一個執(zhí)行,保證了線程的順序執(zhí)行。 -
newScheduledThreadPool
調(diào)度線程池,即按一定的周期執(zhí)行任務(wù),即定時任務(wù),對ThreadPoolExecutor進行了包裝而已。
- Java線程同步和異步
- 同步:單線程執(zhí)行,所有操作都是同步的。
- 異步:并發(fā)都是異步的。
- Java線程之Join、Yield和Sheep,Wait和notify
- Yield:暫停當前線程執(zhí)行,讓其他線程參與競爭,系統(tǒng)選擇其他相同的或者更高優(yōu)先級的線程;
- Join:是當前的線程暫停執(zhí)行,等待調(diào)用該方法的線程結(jié)束后再繼續(xù)執(zhí)行本線程;
- Sleep:屬于Thread類,暫停線程執(zhí)行,線程進入阻塞狀態(tài),讓出CPU,不會釋放對象鎖,到指定時間會自動醒過來;
- Wait:必須在synchronized內(nèi)部執(zhí)行,屬于Object類,暫停線程執(zhí)行,線程進入休眠狀態(tài),釋放對象鎖,加入等待對象池,只有調(diào)用notify()和notifyAll()方法才可以執(zhí)行;
- Java之死鎖
死鎖:死鎖是操作系統(tǒng)層面的一個錯我,是進程死鎖的簡稱。
必要條件:
- 互斥條件:即當資源被一個線程使用,別的線程不能使用。
- 不剝奪條件:資源請求者不能強制從占有者手中奪取資源,資源只能由資源占有者主動釋放。
- 請求和保持:即當資源請求者在請求其他的資源的同時保持對原有資源的占有。
- 循環(huán)等待:即存在一個等待隊列,P1占有P2的資源,P2占有P3的資源,P3占有P1的資源,這樣既形成了一個等待環(huán)路。
- Java之volatile關(guān)鍵字
- 保證了不同線程對這個變量進行操作時的可見性,即一個線程修改了每個變量的值,新值對其他線程來說是立即可見的。
- 禁止進行指令重排序。
- Java同步鎖-synchronized關(guān)鍵字和Lock接口
synchronized:可以修飾靜態(tài)方法、成員函數(shù),還可以直接定義代碼塊
(https://cloud.tencent.com/developer/article/1465413)
- 對成員函數(shù)加鎖,必須獲得該類的實例對象的鎖才能進入同步塊;
- 對靜態(tài)方法加鎖,必須獲得該類的鎖才能進入同步塊;
- 對同步塊加入class,執(zhí)行前必須獲得該class類的鎖;
- 對同步塊加入Instance,執(zhí)行前必須先獲得實例對象的鎖;
- synchronized鎖的實現(xiàn):
有兩種方式:它們的底層實現(xiàn)一樣,在進入同步代碼之前先獲取鎖,獲取到鎖之后鎖的計數(shù)器+1,同步代碼執(zhí)行完鎖的計數(shù)器-1,如果獲取失敗就阻塞式等待鎖的釋放。
同步方式識別不同。
- 對方法上鎖:通過flags標志
- 構(gòu)造同步代碼塊:通過monitorenter和monitorexit指令操作
- synchronized鎖的底層實現(xiàn)原理:
在JVM中,對象分成三部分存在:對象頭、實例數(shù)據(jù)、對其填充。
對象頭是synchronized實現(xiàn)鎖的基礎(chǔ),因為synchronized申請鎖、上鎖、釋放鎖都與對象頭有關(guān)。
對象頭主要結(jié)構(gòu)由Mark Word 和 CLass Metadata Address,其中Mark Word存儲著鎖信息。
JDK6之后,synchronized優(yōu)化之后有四個狀態(tài):無狀態(tài)鎖、偏向鎖、輕量級鎖、重量級鎖,鎖的狀態(tài)在對象頭Mark Word 中都有記錄,在申請鎖、鎖升級等過程中JVM都需要讀取對象的Mark down數(shù)據(jù)。
- synchronized鎖膨脹
偏向鎖:減少統(tǒng)一線程獲取鎖的代價。在大多數(shù)情況下,鎖不存在多線程競爭,總是由同一線程多次獲得,那么此時即使偏向的。
核心思想:如果一個線程獲得了鎖,那么鎖就進入偏向模式,此時 Mark down的結(jié)構(gòu)也就變?yōu)槠蜴i結(jié)構(gòu),當該線程再次請求鎖時,無需再做任何同步操作,即獲取鎖的過程只需要檢查 Mark down的鎖標記位為偏向鎖以及當前線程ID等于Mark down的ThreadID即可。
輕量級鎖:輕量級鎖是由偏向鎖升級而來,當存在第二個線程申請同一個鎖對象時,偏向鎖就會立即升級為輕量級鎖。注意這里的第二個線程只是申請鎖,不存在兩個線程同時競爭鎖,可以是一前一后的交替
執(zhí)行同步塊。
重量級鎖:重量級鎖是由輕量級鎖升級而來,當同一時間有多個線程競爭鎖時,鎖就會被升級成重量級鎖,此時其申請鎖帶來的開銷也就變大。
- 鎖消除:消除鎖是虛擬機另外一種鎖的優(yōu)化,這種優(yōu)化更徹底,在JIT編譯時,對運行上下文進行掃描,
去除不可能存在競爭的鎖。
- 鎖優(yōu)化:鎖粗化是虛擬機對另一種極端情況的優(yōu)化處理,通過擴大鎖的范圍,避免重復加鎖和釋放鎖。
- 自旋鎖:通過讓線程執(zhí)行循環(huán)等待鎖的釋放,不讓出CPU。如果等到鎖,就順利進入臨界區(qū)。如果還不能獲得鎖,那么久掛起。但是如果鎖被其他線程長時間占用,一直不釋放CPU,會帶來許多的性能開銷。
- 自適應自旋鎖:相當于對自旋鎖的進一步優(yōu)化。它的自旋次數(shù)不再固定,其自旋的次數(shù)由前一次在同一個鎖上的自旋時間及鎖的擁有者的狀態(tài)決定,這就解決了自旋鎖帶來的缺點。
- Java之Lock接口
- 定義:是一個接口,用來手動的獲取和釋放鎖,并且發(fā)生異常時不會主動的釋放鎖,所有必須在try...catch塊中,在finally中釋放鎖,保證鎖一定會被釋放,不會發(fā)生死鎖。
-
原理:(https://blog.csdn.net/future234/article/details/80576623)
AQS(隊列同步器,雙向鏈表) + int值 + CAS自旋
- synchronized和lock的區(qū)別
- 首先synchronized是java內(nèi)置關(guān)鍵字,Lock是Java類;
- synchronized無法判斷是否獲取鎖的狀態(tài),Lock可以判斷是否獲取到鎖;
- synchronized會自動釋放鎖,Lock需在finally中手工釋放鎖,否則容易造成線程死鎖;
- synchronized的鎖可重入、不可中斷、非公平。Lock鎖可重入、可判斷、公平和非公平都可實現(xiàn);
- Lock建議使用在低鎖沖突的情況下;
- Java中的引用類型
1、強引用代碼中普遍存在的類似"Object obj = new Object()"這類的引用,只要強引用還存在,垃圾收集器永遠不會回收掉被引用的對象。
2、軟引用描述有些還有用但并非必需的對象。在系統(tǒng)將要發(fā)生內(nèi)存溢出異常之前,將會把這些對象列進回收范圍進行二次回收。如果這次回收還沒有足夠的內(nèi)存,才會拋出內(nèi)存溢出異常。Java中的類SoftReference表示軟引用。
3、弱引用描述非必需對象。被弱引用關(guān)聯(lián)的對象只能生存到下一次垃圾回收之前,垃圾收集器工作之后,無論當前內(nèi)存是否足夠,都會回收掉只被弱引用關(guān)聯(lián)的對象。Java中的類WeakReference表示弱引用。
4、虛引用這個引用存在的唯一目的就是在這個對象被收集器回收時收到一個系統(tǒng)通知,被虛引用關(guān)聯(lián)的對象,和其生存時間完全沒關(guān)系。Java中的類PhantomReference表示虛引用。
- Java集合
- Array:數(shù)組是相同類型數(shù)據(jù)的有序集合,在堆中被分配連續(xù)空間,通過下標尋找,查找速度快,插入慢。
- List:鏈表是一種物理存儲單元上非連續(xù)、非順序的存儲結(jié)構(gòu),數(shù)據(jù)元素的邏輯順序是通過鏈表中的指針連接次序?qū)崿F(xiàn)的。每個鏈表包含多個節(jié)點,節(jié)點包含兩個部分,一個是數(shù)據(jù)域,用來存儲數(shù)據(jù),一個是引用域(相當于指針,雙向鏈表有兩個指針,分別指向上一個和下一個節(jié)點),指向下個節(jié)點。查找慢,插入、刪除快。
- Map:是一種鍵-值對集合,Map集合中的每一個元素都包含一個鍵對象和一個值對象
- ArrayList:
- 內(nèi)部采用數(shù)組實現(xiàn),默認大小10;
- 擴容newCapacity = oldCapacity + (oldCapacity >> 1);
- 擴容時 調(diào)用native System.arrayCopy 方法拷貝;
- 可以存在多個null;
- LinkedList:
- 內(nèi)部采用雙向鏈表存儲;
- 可以存在多個null;
- Vector:
- 內(nèi)部數(shù)組實現(xiàn);
- 默認大小為10,capacityIncrement設(shè)置自增長大小 沒有則自增張一倍;
- 內(nèi)部方法被synchronized修飾,線程安全;
- HashMap:(http://www.itdecent.cn/p/ee0de4c99f87)
- 內(nèi)部由數(shù)組+鏈表+紅黑樹實現(xiàn);
- 默認大小16,默認負載系數(shù)0.75,閾值
threshold = loadFactor(負載系數(shù)) * capacity(容量);- resize()擴容直接擴大一倍
newThr = oldThr << 1; // double threshold;- 當鏈表長度大于8且容量大于64,轉(zhuǎn)紅黑數(shù) 當鏈表長度小于6,還原成數(shù)組;
- 擴容因子默認0.75,是根據(jù)泊松分布(二項分布)測得;
- key和value可以為null,key至多只有一個;
- 樹:樹是一種抽象數(shù)據(jù)類型或是實現(xiàn)這種抽象數(shù)據(jù)類型的數(shù)據(jù)結(jié)構(gòu),用來模擬具有樹狀結(jié)構(gòu)性質(zhì)的數(shù)據(jù)集合。
(http://www.itdecent.cn/p/683ccf7b4712)
特點:
- 每個節(jié)點有零個或多個子節(jié)點;
- 沒有父節(jié)點的節(jié)點稱為根節(jié)點;
- 每個非根節(jié)點有且只有一個父節(jié)點;
- 除了根節(jié)點外,每個子節(jié)點可以分為多個不相交的子樹;
- 二叉樹:每個節(jié)點最多含有兩個子節(jié)點的樹稱為二叉樹
- 滿二叉樹:一顆有n層的二叉樹,除第n層外,每層都有兩個子節(jié)點
- 完全二叉樹:假設(shè)二叉樹有h層,除第好層外,其他各層的節(jié)點數(shù)均已達到最大個數(shù)(1至h-1層為滿二叉樹),第h層所有的節(jié)點都集中在最左邊,這棵樹就是滿二叉樹。
- 二叉查找樹:又稱為二叉搜索樹、有序二叉樹、排序二叉樹
特點:
- 若任意節(jié)點的左子樹不空,則左子樹上所有節(jié)點的值均小于它的跟節(jié)點的值;
- 若任意節(jié)點的右子樹不空,則右子樹上所有節(jié)點的值均大于他的根節(jié)點的值;
- 任意節(jié)點的左、右子樹也分別為二叉查找樹;
- 沒有鍵值相等的點;
- 平衡二叉樹(AVL樹)
因為二叉樹某些情況會退化成鏈條表,時間復雜度O(n),效率低下,這時需要平衡二叉樹。它是嚴格的平衡二叉樹,平衡條件必須滿足,所有只有通過旋轉(zhuǎn)保持平衡,而旋轉(zhuǎn)是非常耗時的,適用于插入和刪除次數(shù)比較少,但查找多的情況。
特點:
- 左樹所有節(jié)點比根節(jié)點小,右樹所有節(jié)點比根節(jié)點大
- 左樹和右樹的高度最大差值為1
- 紅黑樹
通過對任何一條從跟到葉子的路徑上各個節(jié)點著色的方式的限制,紅黑樹確保沒有一條路徑會比其他路徑長出兩倍,它是一種弱平衡二叉樹,相比AVL樹來說,它的旋轉(zhuǎn)次數(shù)少,對于搜索、插入、刪除操作較多的情況下,優(yōu)先用紅黑樹。
特點:
- 每個節(jié)點是黑色或紅色;
- Root節(jié)點一定是黑色;
- Null節(jié)點一定是黑色;
- 不能出現(xiàn)連續(xù)的紅色節(jié)點;
- 從任意一個節(jié)點達到子節(jié)點的黑色數(shù)目相同;
- Java值傳遞和引用傳遞(https://mp.weixin.qq.com/s/Qp6Cc0mlRLnrToNy5-3zeg)
(可以說是Java不同數(shù)據(jù)類型儲存的方式不同導致有值傳遞和引用傳遞這種說法)
形參:方法被調(diào)用時需要傳遞進來的參數(shù),如:func(int a)中的a,它只有在func被調(diào)用期間a才有意義,也就是會被分配內(nèi)存空間,在方法func執(zhí)行完成后,a就會被銷毀釋放空間,也就是不存在了
實參:方法被調(diào)用時是傳入的實際值,它在方法被調(diào)用前就已經(jīng)被初始化并且在方法被調(diào)用時傳入。
值傳遞:在方法被調(diào)用時,實參通過形參把它的內(nèi)容副本傳入方法內(nèi)部,此時形參接收到的內(nèi)容是實參值的一個拷貝,因此在方法內(nèi)對形參的任何操作,都僅僅是對這個副本的操作,不影響原始值的內(nèi)容。
引用傳遞:”引用”也就是指向真實內(nèi)容的地址值,在方法調(diào)用時,實參的地址通過方法調(diào)用被傳遞給相應的形參,在方法體內(nèi),形參和實參指向通愉快內(nèi)存地址,對形參的操作會影響的真實內(nèi)容。
基本數(shù)據(jù)類型:我們聲明并初始化基本數(shù)據(jù)類型的局部變量時,變量名以及字面量值都是存儲在棧中,而且是真實的內(nèi)容。在值傳遞過程中,我們知道棧幀是私有的、獨立的,傳遞過去的值是拷貝過去的副本,然后繼續(xù)修改變量的值,不會影響原值。
引用數(shù)據(jù)類型:”引用”也就是指向真實內(nèi)容的地址值,在方法調(diào)用時,實參的地址通過方法調(diào)用被傳遞給相應的形參,在方法體內(nèi),形參和實參指向通愉快內(nèi)存地址,對形參的操作會影響的真實內(nèi)容。引用傳遞,也是拷貝副本,但是它們的引用地址指向同一個,看起來像是同一個,實際上重新new一個對象會發(fā)現(xiàn),原來的對象沒有改變。
在Java中所有的參數(shù)傳遞,不管基本類型還是引用類型,都是值傳遞,或者說是副本傳遞。
只是在傳遞過程中:
如果是對基本數(shù)據(jù)類型的數(shù)據(jù)進行操作,由于原始內(nèi)容和副本都是存儲實際值,并且是在不同的棧區(qū),因此形參的操作,不影響原始內(nèi)容。
如果是對引用類型的數(shù)據(jù)進行操作,分兩種情況,一種是形參和實參保持指向同一個對象地址,則形參的操作,會影響實參指向的對象的內(nèi)容。一種是形參被改動指向新的對象地址(如重新賦值引用),則形參的操作,不會影響實參指向的對象的內(nèi)容。