1再膳、進程和線程
地址空間和其他資源:進程間相互獨立,進程中包括多個線程,線程間共享進程資源爽雄,某進程內(nèi)的線程在其他進程內(nèi)不可見
通信:進程間通信通過IPC機制,線程間通信通過數(shù)據(jù)段(如:全局變量)的讀寫灰蛙,需要進程同步和互斥手段的輔助键兜,以保證數(shù)據(jù)的一致性
調(diào)度和切換:進程是資源分配單位委粉,線程是cpu調(diào)度單位野芒,跟cpu真正打交道的是線程蓄愁,線程上下文切換比進程上下文切換要快得多
2、內(nèi)存溢出和內(nèi)存泄漏
內(nèi)存溢出:指程序在申請內(nèi)存時狞悲,沒有足夠的空間供其使用
內(nèi)存泄漏:指程序分配出去的內(nèi)存不再使用,無法進行回收
4妇斤、Java的四個基本特性
抽象:現(xiàn)實生活中的事物被抽象成對象摇锋,把具有相同屬性和行為的對象被抽象成類丹拯,再從具有相同屬性和行為的類中抽象出父類。
封裝:隱藏對象的屬性和實現(xiàn)細節(jié)荸恕,僅僅對外公開接口乖酬。
封裝具有一下優(yōu)點:
便于使用者正確、方便的使用系統(tǒng)融求,防止使用者錯誤修改系統(tǒng)屬性咬像;
有助于建立各個系統(tǒng)之間的松耦合關(guān)系;
提高軟件的可重用性生宛;
降低了大型系統(tǒng)的風險县昂,即便整個系統(tǒng)不成功,個別獨立的子系統(tǒng)有可能還有價值陷舅。
封裝的兩大原則:
把盡可能多的東西藏起來倒彰,對外提供簡潔的接口;
把所有的屬性封裝起來莱睁。
繼承:子類和父類之間的繼承關(guān)系待讳,子類可以獲取到父類的屬性和方法。
多態(tài):java語言允許某個類型的引用變量引用子類的實例仰剿,而且可以對這個引用變量進行類型轉(zhuǎn)換创淡。
5、抽象類和接口的區(qū)別
抽象類和接口分別給出了不同的語法定義(包括方法體南吮、成員變量修飾符辩昆、方法修飾符)
抽象是對類的抽象,接口是對行為的抽象
抽象是自底向上抽象的旨袒,接口是自頂向下設(shè)計出來的
抽象所體現(xiàn)的是繼承關(guān)系汁针,是一種”is-a”的關(guān)系,接口僅僅實現(xiàn)接口定義的契約砚尽,是一種”like-a”的關(guān)系
6施无、自動裝箱與拆箱
Java采用了自動裝箱和拆箱機制,節(jié)省了常用數(shù)值的內(nèi)存開銷和創(chuàng)建對象的開銷必孤,提高了效率
裝箱:將基本數(shù)據(jù)類型包裝成它們的引用類型
拆箱:將包裝類型轉(zhuǎn)換成基本數(shù)據(jù)類型
7猾骡、序列化與反序列化
對象的序列化:是把對象轉(zhuǎn)換成字節(jié)序列的過程
對象的反序列化:是把字節(jié)序列恢復為對象的過程
對象序列化的主要用途:
可以將字節(jié)序列永久的保存在硬盤中,通常放在文件中
可以在網(wǎng)絡(luò)上傳送字節(jié)序列
兩個線程在進行遠程通信時敷搪,彼此可以發(fā)送各種類型兴想。發(fā)送方需要把這個Java對象轉(zhuǎn)換為字節(jié)序列,接收方則需要把字節(jié)序列再恢復為Java對象
8赡勘、編譯和運行
1嫂便、編譯時和運行時
編譯時:將Java文件編譯成.class文件的過程,不涉及到內(nèi)存的分配
運行時:將虛擬機執(zhí)行.class文件的過程闸与,涉及到內(nèi)存的分配
2毙替、編譯時類型和運行時類型
編譯時類型:由聲明該變量時使用的類型決定
運行時類型:由實際賦給該變量的對象決定
3岸售、編譯時和運行時的動態(tài)綁定
在編譯時,調(diào)用的是聲明類型的成員方法
在運行時厂画,調(diào)用的是實際類型的成員方法
對于調(diào)用引用實例的成員變量凸丸,無論是編譯還是運行時,均是編譯時類型的成員變量
9袱院、GC簡述
當程序員創(chuàng)建對象時屎慢,GC就開始監(jiān)控這個對象的地址、大小以及使用情況忽洛。通常腻惠,GC采用有向圖的方式記錄和管理堆(heap)中的所有對象,通過這種方式確定哪些對象是”可達的”脐瑰,哪些對象是”不可達的”妖枚。當GC確定一些對象為”不可達”時,GC就有責任回收這些內(nèi)存空間苍在。但是绝页,為了保證
GC能夠在不同平臺實現(xiàn)的問題,Java規(guī)范對GC的很多行為都沒有進行嚴格的規(guī)定
10寂恬、serialVersionUID簡述
對于實現(xiàn)java.io.Serializable接口的實體類來說续誉,往往都會手動聲明serialVersionUID,因為只要你實現(xiàn)了序列化初肉,java自己就會默認給實體類加上一個serialVersionUID酷鸦。java默認添加的serialVersionUID是會根據(jù)實體類的成員(成員變量,成員方法)變化而變化牙咏。當我們把實體類序列化到本地后臼隔,如果實體類的成員發(fā)生了變化,默認添加的serialVersionUID就會發(fā)生變化妄壶。此時硬盤上序列化對象的serialVersionUID與實體類中的serialVersionUID對不上摔握,就會反序列化失敗爆出異常。所以丁寄,通常對于實現(xiàn)了SerialVersionUID接口的實體類來說氨淌,都會手動聲明serialVersionUID
11、Java中4種引用類型
StrongReference(強引用):從不回收伊磺,對象一直存在盛正,當JVM停止的時候才被終止
SoftReference(軟引用):可以和引用隊列(ReferenceQueue)聯(lián)合使用,當內(nèi)存不足時被終止
WeakReference(弱引用):可以和引用隊列(ReferenceQueue)聯(lián)合使用屑埋,當內(nèi)存不足時豪筝,觸發(fā)GC后被終止
PhantomReference(虛引用):必須和引用隊列(ReferenceQueue)聯(lián)合使用,隨時會被回收,觸發(fā)GC后被終止
SoftReference和WeakReference的區(qū)別:
WeakReference的生命周期比SoftReference的生命周期短
SoftReference多用于圖片的緩存壤蚜,而WeakReference多用于內(nèi)存泄漏的解決
WeakReference可以通過手動GC進行清除
字符串相關(guān)面試題
1即寡、String徊哑、StringBuffer和StringBuilder
1袜刷、可變性
String類是用字符數(shù)組保存字符串,即private final char value[]莺丑,所以String對象不可變
StringBuffer類與StringBuilder類都是繼承AbstractStringBuilder類著蟹,AbstractStringBuilder是用字符數(shù)組保存字符串,即char value[]梢莽,所以StringBuffer與StringBuilder對象是可變的
2萧豆、線程安全性
String類對象不可變,所以理解為常量昏名,線程安全
StringBuffer類對方法加了同步鎖涮雷,線程安全
StringBuilder類對方法未加同步鎖,線程不安全
3轻局、性能
String類進行改變的時候洪鸭,都會產(chǎn)生新的String對象,然后將指針指向新的String對象
StringBuffer進行改變的時候仑扑,都會復用自身對象览爵,性能比String高
StringBuilder行改變的時候,都會復用自身對象镇饮,相比StringBuffer能獲得10%~15%左右的性能提升蜓竹,但是得承擔多線程的不安全的風險
2、構(gòu)造器Constructor是否可被override
構(gòu)造器不能被重寫
構(gòu)造器不能被static修飾
構(gòu)造器只能用private储藐、protected俱济、public修飾
構(gòu)造器不能有返回值
3、String類是否可以繼承
String類由final類钙勃,故不可以繼承蛛碌,凡是由final修飾的類都不能繼承
集合相關(guān)面試題
可查看我的博客,按順序閱讀肺缕,需要您具備數(shù)據(jù)結(jié)構(gòu)基礎(chǔ)左医,且基于JDK1.7
Java基礎(chǔ)——HashMap源碼分析及面試題解答
Java基礎(chǔ)——HashSet源碼分析
Java基礎(chǔ)——HashTable源碼分析
Java基礎(chǔ)——LinkedHashMap源碼分析
Java基礎(chǔ)——LinkedHashSet源碼分析
Java基礎(chǔ)——ArrayList源碼分析
Java基礎(chǔ)——LinkedList源碼分析
Java基礎(chǔ)——ConcurrentHashMap源碼分析
Java基礎(chǔ)——Vector源碼分析
1、TreeMap和HashMap
TreeMap ?? ?HashMap
有序的 ?? ?無序的
不允許null ?? ?允許null
實現(xiàn)Comparable接口 ?? ?不實現(xiàn)Comparable接口
底層是紅黑二叉樹同木,線程不同步 ?? ?底層是哈希表浮梢,線程不同步
2、TreeSet和HashSet
TreeSet ?? ?HashSet
有序的 ?? ?無序的
不允許null ?? ?允許null
底層是紅黑二叉樹彤路,線程不同步 ?? ?底層是哈希表秕硝,線程不同步
TreeSet是通過TreeMap實現(xiàn)的,用的只是Map的key ?? ?HashSet是通過HashMap實現(xiàn)的洲尊,用的只是Map的key
3远豺、Collection和Collections
Collection:是一個集合接口奈偏,它提供了對集合對象進行基本操作的通用接口方法
Collections:是一個集合的工具類,它包含有各種有關(guān)集合操作的靜態(tài)方法
4躯护、hashCode和equals
equals相等惊来,hashCode必相等;hashCode相等棺滞,equals不一定相等
錯誤相關(guān)面試題
1裁蚁、Error和Exception
Error類和Exception類的父類都是throwable類
Error:一般指與虛擬機相關(guān)的問題,如系統(tǒng)崩潰继准,虛擬機錯誤枉证,內(nèi)存空間不足,方法調(diào)用棧溢等移必。對于這類錯誤導致的應(yīng)用程序中斷室谚,僅靠程序本身無法恢復和和預(yù)防,遇到這樣的錯誤崔泵,建議讓程序終止
Exception:表示程序可以處理的異常秒赤,可以捕獲且可能恢復。遇到這類異常管削,應(yīng)該盡可能處理異常倒脓,使程序恢復運行,而不應(yīng)該隨意終止異常
2含思、Unchecked Exception和Checked Exception
1崎弃、Unchecked Exception
指的是不可被控制的異常,或稱運行時異常含潘,主要體現(xiàn)在程序的瑕疵或邏輯錯誤饲做,并且在運行時無法恢復
包括Error與RuntimeException及其子類,如:OutOfMemoryError遏弱,IllegalArgumentException盆均, NullPointerException,IllegalStateException漱逸,IndexOutOfBoundsException等
語法上不需要聲明拋出異常也可以編譯通過
2泪姨、Checked Exception
指的是可被控制的異常,或稱非運行時異常
除了Error和RuntimeException及其子類之外饰抒,如:ClassNotFoundException, NamingException, ServletException, SQLException, IOException等
需要try catch處理或throws聲明拋出異常
數(shù)據(jù)相關(guān)面試題
1肮砾、xml解析方式
Dom解析:將XML文件的所有內(nèi)容讀取到內(nèi)存中(內(nèi)存的消耗比較大),然后允許您使用DOM API遍歷XML樹袋坑、檢索所需的數(shù)據(jù)
Sax解析:Sax是一個解析速度快并且占用內(nèi)存少的xml解析器仗处,Sax解析XML文件采用的是事件驅(qū)動,它并不需要解析完整個文檔,而是按內(nèi)容順序解析文檔的過程
Pull解析:Pull解析器的運行方式與 Sax 解析器相似婆誓。它提供了類似的事件吃环,可以使用一個switch對感興趣的事件進行處理
詳細可見我的博客:Android基礎(chǔ)——XML數(shù)據(jù)的三種解析方式
線程相關(guān)面試題
1、線程實現(xiàn)的方式
繼承Thread類洋幻、實現(xiàn)Runnable接口郁轻、使用ExecutorService、Callable鞋屈、Future實現(xiàn)有返回結(jié)果的線程
2范咨、如何停止一個線程
創(chuàng)建一個標識(flag)故觅,當線程完成你所需要的工作后厂庇,可以將標識設(shè)置為退出標識
使用Thread的stop()方法,這種方法可以強行停止線程输吏,不過已經(jīng)過期了权旷,因為其在停止的時候可能會導致數(shù)據(jù)的紊亂
使用Thread的interrupt()方法和Thread的interrupted()方法,兩者配合break退出循環(huán)贯溅,或者return來停止線程拄氯,有點類似標識(flag)
(推薦)當我們想要停止線程的時候,可以使用try-catch語句它浅,在try-catch語句中拋出異常译柏,強行停止線程進入catch語句,這種方法可以將錯誤向上拋姐霍,使線程停止事件得以傳播
3鄙麦、線程的狀態(tài)轉(zhuǎn)換
這里寫圖片描述
1、新建(new):創(chuàng)建了一個線程對象
2镊折、可運行(runnable):線程對象創(chuàng)建后胯府,線程調(diào)用start()方法。該狀態(tài)的線程位于可運行線程池中恨胚,等待被線程調(diào)度選中骂因,獲取cpu的使用權(quán)
3、運行(running):可運行狀態(tài)(runnable)的線程獲得了cpu使用權(quán)赃泡,執(zhí)行程序代碼
4寒波、阻塞(block):線程因為某種原因放棄了cpu使用權(quán),即讓出了cpu使用權(quán)升熊,暫時停止運行俄烁,直到線程進入可運行(runnable)狀態(tài),才有機會再次獲得cpu使用權(quán)轉(zhuǎn)到運行(running)狀態(tài)僚碎。阻塞的情況分三種:
等待阻塞:運行(running)的線程執(zhí)行o.wait()方法猴娩,JVM會把該線程放入等待隊列(waitting queue)中
同步阻塞:運行(running)的線程在獲取對象的同步鎖時,若該同步鎖被別的線程占用,則JVM會把該線程放入鎖池(lock pool)中
其他阻塞:運行(running)的線程執(zhí)行Thread.sleep(long ms)或t.join()方法卷中,或者發(fā)出了I/O請求時矛双,JVM會把該線程置為阻塞狀態(tài)。當sleep()狀態(tài)超時蟆豫、join()等待線程終止或者超時议忽、或者I/O處理完畢時,線程重新轉(zhuǎn)入可運行(runnable)狀態(tài)
5十减、死亡(dead):線程run()栈幸、main() 方法執(zhí)行結(jié)束,或者因異常退出了run()方法帮辟,則該線程結(jié)束生命周期速址,且死亡的線程不可再次復生
4、什么是線程安全
在多線程訪問同一代碼的時候由驹,不會出現(xiàn)不確定的結(jié)果
5芍锚、如何保證線程安全
對非安全的代碼進行加鎖操作
使用線程安全的類
不要跨線程訪問共享變量
使用final類型作為共享變量
對共享變量加鎖操作
6、Synchronized如何使用
Synchronized是Java的關(guān)鍵字蔓榄,是一種同步鎖并炮,它可以修飾的對象有以下幾種
修飾代碼塊:該代碼塊被稱為同步代碼塊,作用的主要對象是調(diào)用這個代碼塊的對象
修飾方法:該方法稱為同步方法甥郑,作用的主要對象是調(diào)用這個方法的對象
修飾靜態(tài)方法:作用范圍為整個靜態(tài)方法逃魄,作用的主要對象為這個類的所有對象
修飾類:作用范圍為Synchronized后面括號括起來的部分,作用的主要對象為這個類的所有對象
7澜搅、Synchronized和Lock的區(qū)別
相同點:Lock能完成Synchronized所實現(xiàn)的所有功能
不同點:
Synchronized是基于JVM的同步鎖伍俘,JVM會幫我們自動釋放鎖。Lock是通過代碼實現(xiàn)的店展,Lock要求我們手工釋放养篓,必須在finally語句中釋放。
Lock鎖的范圍有局限性赂蕴、塊范圍柳弄。Synchronized可以鎖塊、對象概说、類
Lock功能比Synchronized強大碧注,可以通過tryLock方法在非阻塞線程的情況下拿到鎖
8、多線程的等待喚醒主要方法
void notify():喚醒在此對象監(jiān)視器上等待的單個線程
void notifyAll():喚醒在此對象監(jiān)視器上等待的所有線程
void wait():導致當前的線程等待糖赔,直到其他線程調(diào)用此對象的notify()方法或notifyAll()方法
void wait(long timeout):導致當前的線程等待萍丐,直到其他線程調(diào)用此對象的notify()方法或notifyAll()方法,或者超過指定的時間量
void wait(long timeout, int nanos):導致當前的線程等待放典,直到其他線程調(diào)用此對象的notify()方法或notifyAll()方法逝变,或者其他某個線程中斷當前線程基茵,或者已超過某個實際時間量
9、sleep和wait的區(qū)別
sleep() ?? ?wait()
是Thread類的方法 ?? ?是Object類中的方法
調(diào)用sleep()壳影,在指定的時間里拱层,暫停程序的執(zhí)行,讓出CPU給其他線程宴咧,當超過時間的限制后根灯,又重新恢復到運行狀態(tài),在這個過程中掺栅,線程不會釋放對象鎖 ?? ?調(diào)用wait()時烙肺,線程會釋放對象鎖,進入此對象的等待鎖池中氧卧,只有此對象調(diào)用notify()時桃笙,線程進入運行狀態(tài)
10、多線程中的死鎖
死鎖:指兩個或兩個以上的線程在執(zhí)行的過程中假抄,因搶奪資源而造成互相等待怎栽,導致線程無法進行下去
產(chǎn)生死鎖的4個必要條件
循環(huán)等待:線程中必須有循環(huán)等待
不可剝奪:線程已獲得資源,再未使用完成之前宿饱,不可被剝奪搶占
資源獨占:線程在某一時間內(nèi)獨占資源
申請保持:線程因申請資源而阻塞,對已獲得的資源保持不放
11脚祟、什么叫守護線程谬以,用什么方法實現(xiàn)守護線程
守護線程:指為其他線程的運行提供服務(wù)的線程,可通過setDaemon(boolean on)方法設(shè)置線程的Daemon模式由桌,true為守護模式为黎,false為用戶模式
12、Java中的BIO行您,NIO铭乾,AIO分別是什么,應(yīng)用場景是什么
BIO:同步并阻塞娃循,服務(wù)器實現(xiàn)模式是一個連接對應(yīng)一個線程炕檩,即客戶端有連接請求時,服務(wù)器就會開啟一個線程進行處理捌斧,如果這個連接不做任何事情時笛质,會造成不必要的線程開銷,可以使用線程池進行改善捞蚂。其應(yīng)用場景適用于連接數(shù)目比較小且固定的架構(gòu)妇押,這種方式對服務(wù)器資源要求較高,對線程并發(fā)有局限性
NIO:同步非阻塞姓迅,服務(wù)器實現(xiàn)模式是一個請求對應(yīng)一個線程敲霍,即客戶端的連接請求都會注冊在多路復用器上俊马,當多路復用器輪詢到有I/O請求時才啟動一個線程進行處理。其應(yīng)用場景適用于連接數(shù)目多且連接短的架構(gòu)肩杈,對線程并發(fā)有局限性
AIO:異步非阻塞潭袱,服務(wù)器實現(xiàn)模式是一個有效請求對應(yīng)一個線程,即客戶端的I/O請求完成之后锋恬,再通知服務(wù)器去啟動一個線程進行處理屯换。其應(yīng)用場景適用于連接數(shù)目多且連接長的架構(gòu),充分體現(xiàn)出并發(fā)性
13与学、Java中的IO和NIO的區(qū)別
IO是面向流的彤悔,NIO是面向緩沖區(qū)的
IO的各種流是阻塞的,NIO是非阻塞模式
14索守、volatile關(guān)鍵字
用volatile修飾的變量晕窑,線程在每次修改變量的時候,都會讀取變量修改后的值卵佛,可以簡單的理解為volatile修飾的變量保存的是變量的地址杨赤。volatile變量具有synchronized的可見性,但是不具備原子性
可見性:在多線程并發(fā)的條件下截汪,對于變量的修改疾牲,其他線程中能獲取到修改后的值
原子性:在多線程并發(fā)的條件下,對于變量的操作是線程安全的衙解,不會受到其他線程的干擾
volatile不是線程安全的阳柔,要使volatile變量提供理想的線程安全,必須同時滿足下面兩個條件
對變量的寫操作不依賴于當前值
該變量沒有包含在具有其他變量的不變式中
比如增量操作(x++)看上去類似一個單獨操作蚓峦,實際上它是一個由[讀壬嗉痢-修改-寫入]操作序列組成的組合操作,必須以原子方式執(zhí)行暑椰,而volatile不能提供必須的原子特性霍转。實現(xiàn)正確的操作,應(yīng)該使x的值在操作期間保持線程安全一汽,而volatile變量無法實現(xiàn)這點
然而避消,Java提供了java.util.concurrent.atomic.*包下的變量或引用,讓變量或?qū)ο蟮牟僮骶哂性有越浅妫诟卟l(fā)的情況下沾谓,依然能保持獲取到最新修改的值,常見的有AtomicBoolean戳鹅、AtomicReference等
volatile原理:對于值的操作均驶,會立即更新到主存中,當其他線程獲取最新值時會從主存中獲取
atomic原理:對于值的操作枫虏,是基于底層硬件處理器提供的原子指令妇穴,保證并發(fā)時線程的安全
反射相關(guān)面試題
1爬虱、什么是反射
在運行狀態(tài)中,對于任意一個類腾它,都可以獲得這個類的所有屬性和方法跑筝,對于任意一個對象,都能夠調(diào)用它的任意一個方法和屬性
2瞒滴、反射使用步驟
獲取類的字節(jié)碼(getClass()曲梗、forName()、類名.class)
根據(jù)類的方法名或變量名妓忍,獲取類的方法或變量
執(zhí)行類的方法或使用變量虏两,如果不使用,也可以創(chuàng)建該類的實例對象(通過獲取構(gòu)造函數(shù)執(zhí)行newInstance方法)
進程相關(guān)面試題
1世剖、進程的優(yōu)先級
優(yōu)先級從低到高排列定罢,優(yōu)先級最高的進程,最先獲取資源旁瘫,最后釋放
1祖凫、空進程
這是Android系統(tǒng)優(yōu)先殺死的,因為此時該進程已經(jīng)沒有任何用途
2酬凳、后臺進程
包含不可見的Activity惠况,即跳轉(zhuǎn)到其他Activity后,由于資源不足粱年,系統(tǒng)會將原來的Activity殺死(即跳轉(zhuǎn)的來源)
3售滤、服務(wù)進程
即Service,當系統(tǒng)資源不足時台诗,系統(tǒng)可能會殺掉正在執(zhí)行任務(wù)的Service,因此在Service執(zhí)行比較耗時的操作赐俗,并不能保證一定能執(zhí)行完畢
4拉队、可見進程
當前屏幕上可以看到的Activity,例如顯示一個對話框的Activity阻逮,那么對話框變成了前臺進程粱快,而調(diào)用他的Activity是可見進程,但并不是前臺的
5叔扼、前臺進程
當前處于最前端的Activity事哭,也就是Android最后考慮殺死的對象,一般來說瓜富,前臺進程Android系統(tǒng)是不會殺死的鳍咱,只有當前4個都殺掉資源依舊不夠才可能會發(fā)生
2、IPC機制
這里寫圖片描述
類加載器相關(guān)面試題
1与柑、什么是類加載器
ClassLoader是用來動態(tài)加載class文件到內(nèi)存中
2谤辜、類加載器類型
App ClassLoader(應(yīng)用類加載器或系統(tǒng)加載器):這個加載器使用java實現(xiàn)蓄坏,使用廣泛,負責加載classPath中指定的類丑念。具體的使用場合涡戳,在加載classPath中指定的而擴展類加載器沒有加載的類,若擴展類加載器加載了classPath中的類脯倚,則系統(tǒng)類加載器則沒有機會加載渔彰。用戶定義的類一般都是系統(tǒng)類加載器加載的⊥普可以通過:ClassLoader.getSystemClassLoader()獲得
Extension ClassLoader(擴展類加載器):它負責加載Java的標準擴展恍涂,一般使用Java實現(xiàn)的,負責加載jre/lib/ext中的類舔稀。和普通的類加載器一樣乳丰。可以通過:ClassLoader.getSystemClassLoader().getParent()獲得
BootStrap ClassLoader(引導類加載器):純C++實現(xiàn)的加載器内贮,沒有對應(yīng)的Java類产园,它負責加載jdk中jre/lib目錄下的系統(tǒng)核心庫。對于java程序無法獲得它夜郁,像上文中獲得擴展類加載器的父類加載器是null什燕。像String,Integer竞端,Double類都是由引導類加載器加載的
3屎即、雙親委托模型(父委托加載機制)
當加載一個類時,首先會判斷當前類是否已經(jīng)被加載事富,如果被加載直接返回當前類加載器技俐,如果沒有被加載,則把機會讓給父類统台,先讓父類加載雕擂,若是父類中不能加載,則會去找到Bootstrap加載器贱勃,如果Bootstrap加載器加載失敗井赌,則會退回上層,自己通過findClass自己去加載對應(yīng)的路徑(這是孝順型的贵扰,先想到父類仇穗,但是他們不是通過繼承來實現(xiàn)的)
這里寫圖片描述
具體實現(xiàn)代碼在ClassLoader類中的loadClass方法中,API19和API24加載過程有少許區(qū)別(以下是API24的源碼)戚绕,但大部分是一致的纹坐,下面執(zhí)行的邏輯與我們上面所說的一致
protected Class loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
//首先會判斷當前類是否已經(jīng)被加載
Class c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
//把機會讓給父類,先讓父類加載
c = parent.loadClass(name, false);
} else {
//如果父類無法加載列肢,則會去找Bootstrap加載器
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
}
if (c == null) {
long t1 = System.nanoTime();
//如果前面的都加載失敗恰画,則調(diào)用findClass用自己的加載器加載
c = findClass(name);
}
}
return c;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
優(yōu)點:
??? 父委托機制會先去加載系統(tǒng)自帶的class宾茂,而不會去加載我們自定義的高仿的系統(tǒng)class(比如ArrayList),可以保證我們的程序的安全而不會被惡意注入
4拴还、類加載過程
這里寫圖片描述
加載:將類的信息從文件中獲取并且載入到JVM內(nèi)存中
驗證:檢查讀入的結(jié)構(gòu)是否符合JVM規(guī)范的描述
準備:分配一個結(jié)構(gòu)用來存儲類信息
解析:把這個類的常量池的所有符號引用改變成直接引用
初始化:執(zhí)行靜態(tài)初始化程序跨晴、類構(gòu)造器方法的過程
5、自定義類加載器
public class MyClassLoader extends DexClassLoader {
public MyClassLoader(String dexPath, String optimizedDirectory, String librarySearchPath, ClassLoader parent) {
super(dexPath, optimizedDirectory, librarySearchPath, parent);
}
@Override
protected Class findClass(String name) throws ClassNotFoundException {
byte[] classData = getClassData(name);
if (classData != null) {
return defineClass(name, classData, 0, classData.length);
} else {
throw new ClassNotFoundException();
}
}
/**
* 讀取文件的字節(jié)數(shù)組
*
* @param name
* @return
*/
private byte[] getClassData(String name) {
try {
InputStream inputStream = new FileInputStream(name);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int buffSize = 4096;
byte[] buffer = new byte[buffSize];
int bytesRead = -1;
while ((bytesRead = inputStream.read(buffer)) != -1) {
baos.write(buffer, 0, bytesRead);
}
return baos.toByteArray();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
6片林、類加載主要方法的區(qū)別
findClass():查找指定路徑下的class文件
loadClass():加載class字節(jié)碼文件
defineClass():將字節(jié)數(shù)組流轉(zhuǎn)換成字節(jié)碼
易錯題
1端盆、靜態(tài)代碼塊、構(gòu)造代碼塊费封、構(gòu)造方法的執(zhí)行順序
class Fu{
static {
System.out.println("父靜態(tài)代碼塊");
}
{
System.out.println("父代碼塊");
}
public Fu(){
System.out.println("父構(gòu)造函數(shù)");
}
}
class Zi extends Fu{
static {
System.out.println("子靜態(tài)代碼塊");
}
{
System.out.println("子代碼塊");
}
public Zi(){
System.out.println("子構(gòu)造函數(shù)");
}
}
public class Text{
public static void main(String[] args) {
Zi zi = new Zi();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
輸出結(jié)果
父靜態(tài)代碼塊
子靜態(tài)代碼塊
父代碼塊
父構(gòu)造函數(shù)
子代碼塊
子構(gòu)造函數(shù)
---------------------
作者:Hensen_
來源:CSDN
原文:https://blog.csdn.net/qq_30379689/article/details/72550701
版權(quán)聲明:本文為博主原創(chuàng)文章焕妙,轉(zhuǎn)載請附上博文鏈接!