一文理解class.getClassLoader().getResourceAsStream(file)和class.getResourceAsStream(file)區別

FeelTouch發表於2018-11-07

基礎理解

都是實現獲取在classpath路徑下的資原始檔的輸入流。

為什麼是classpath而不是src,因為當web專案執行時,IDE編譯器會把src下的一些資原始檔移至WEB-INF/classes,classPath目錄其實就是這個classes目錄。這個目錄下放的一般是web專案執行時的class檔案、資原始檔(xml,properties...);

另外,在使用springboot進行開發時,其目錄預設不是WEB-INF而是BOOT-INF,但是其含義是一樣的。具體如下圖所示:

上圖,藍框中即為classpath中的內容,也就是自己實際編寫的程式碼,另外以來的程式碼主要再lib目錄下。從另外一個視角對比下,編譯前後檔案所在目錄的變化

編譯前:

編譯後:

class是獲取當前類的class物件,getClassLoader()是獲取當前的類載入器,什麼是類載入器?簡單點說,就是用來載入java類的,類載入器就是負責把class檔案載入進記憶體中,並建立一個java.lang.Class類的一個例項,也就是class物件,並且每個類的類載入器都不相同.getResourceAsStream(path)是用來獲取資源的,因為這是ClassLoader(類載入器)了獲取資源,而類載入器預設是從classPath下獲取資源的,因為這下面有class檔案.所以這段程式碼總的意思是通過類載入器在classPath目錄下獲取資源.並且是以流的形式。我們知道在Java中所有的類都是通過載入器載入到虛擬機器中的,而且類載入器之間存在父子關係,就是子知道父,父不知道子,這樣不同的子載入的型別之間是無法訪問的(雖然它們都被放在方法區中),所以在這裡通過當前類的載入器來載入資源也就是保證是和類型別同一個載入器載入的。 

不同點

class.getClassLoader().getResourceAsStream(String name)

 預設從classpath中找檔案(檔案放在resources目錄下),name不能帶“/”,否則會拋空指標

eg:

InputStream stream = Thread.currentThread().getContextClassLoader().getResourceAsStream("/gamvanclub.cfg.xml");

class.getResourceAsStream(String name)

 查詢資源通過給定名稱,查詢資源的規則與給定的類的class load來實現,這個方法由類的loader來執行,如果這個類由bootstrap載入,那麼方法由ClassLoader.getSystemResourceAsStream代理執行。

 代理之前,絕對的資源名稱通過傳入的name引數以下演算法進行構造:

 如果name以"/"開頭,那麼絕對路徑是/後邊跟的名字

eg:

//從classpath下的config相對路徑中讀取config.ini"
mypackage.Hello.class.getResourceAsStream("/config/config.ini");

 如果name不是以"/"開頭,那麼絕對路徑是package名"."換成“/”以後再加name。

eg:

//com.abc.App就是/com/abc/App/name 或者寫作 : ../../name(以class所在路徑為基準,檔案相對於該類的路徑)

Java類載入過程

3個步驟:

1.載入,載入類的二進位制檔案。

2.連結:

  (1)驗證,驗證位元組碼的結構是否正確

  (2)準備,給靜態成員分配空間並賦予預設值(注意這裡:靜態變數的第一次賦值是在類載入的時候就進行了,與後面初始化的時候的自定義賦值不是同一過程,也就是靜態成員在初始化的時候可能已被賦值二次了)

  (3)解析,將符號引用變為直接引用

3初始化,為靜態成員賦予自己給定的初值

類的例項化的順序:

(1)靜態成員、方法與靜態程式碼塊的初始化與執行

(2)普通成員、方法與普通程式碼塊的初始化與執行

(3)建構函式的執行(父類的建構函式先執行)

相關文章