国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
getClass()和getClassLoader()區(qū)別 以及ClassLoader詳解及用途(文件加載,類加載)

獲得ClassLoader的幾種方法可以通過如下3種方法得到ClassLoader
this.getClass().getClassLoader(); // 使用當(dāng)前類的ClassLoader
Thread.currentThread().getContextClassLoader(); // 使用當(dāng)前線程的ClassLoader
ClassLoader.getSystemClassLoader(); // 使用系統(tǒng)ClassLoader,即系統(tǒng)的入口點所使用的ClassLoader。(注意,system ClassLoader與根ClassLoader并不一樣。JVM下system ClassLoader通常為App ClassLoader)

路徑區(qū)別:
在使用ClassLoader.getResourceAsStream時, 路徑直接使用相對于classpath的絕對路徑.不加"/"
Class.getResourceAsStream()是相對路徑。

----------------------------------------------------------------

Class.getResourse()和Class.getClassLoader().getResource()
這兩個getResource()是使用當(dāng)前ClassLoader加載資源(即資源在 Class path中),這樣資源和class直接打在jar包中,避免文件路徑問題.兩者不同是Class的getResource()方法是從當(dāng)前.class 文件路徑查找資源,ClassLoader則是從jar包根目錄查找.

Class.getResource()
public java.net.URL getResource(String name)查找?guī)в薪o定名稱的資源.查找與給定類相關(guān)的資源的規(guī)則是通過定義類的 class loader 實現(xiàn)的.此方法委托給此對象的類加載器.如果此對象通過引導(dǎo)類加載器加載,則此方法將委托給 ClassLoader.getSystemResource(java.lang.String).
在委托前,使用下面的算法從給定的資源名構(gòu)造一個絕對資源名:

ClassLoader.getResource()
public URL getResource(String name)查找具有給定名稱的資源.資源是可以通過類代碼以與代碼基無關(guān)的方式訪問的一些數(shù)據(jù)(圖像、聲音、文本等). 資源名稱是以 ‘/’ 分隔的標(biāo)識資源的路徑名稱.
此方法首先搜索資源的父類加載器;如果父類加載器為 null,則搜索的路徑就是虛擬機(jī)的內(nèi)置類加載器的路徑.如果搜索失敗,則此方法將調(diào)用 findResource(String) 來查找資源.

兩個方法的區(qū)別是資源的定義不同, 主要用于相對與一個object取資源,而另一個用于取相對于classpath的資源,用的是絕對路徑.
在使用Class.getResourceAsStream 時,資源路徑有兩種方式,一種以/開頭,則這樣的路徑是指定絕對路徑,如果不以/開頭,則路徑是相對與這個class所在的包的.
在使用ClassLoader.getResourceAsStream時, 路徑直接使用相對于classpath的絕對路徑.

project
|-src
|-com.xx.test
|-Main.java
|-b.bmp
|-resource
|-com.icon
|-a.bmp
Main.class.getResource("/icon/a.bmp"); // NOT icon/a.bmp
Main.class.getResource("b.bmp");
// need to add resource/a.bmp to build path! it will be package in jar file
Main.class.getClassLoader().getResource("icon/a.bmp");
// NOT /icon/a.bmp or a.bmp
Thread.currentThread().getContextClassLoader().getResource("icon/a.bmp");

--------------------------------------------------------------------------------------------------------

getClassLoader()報 java.lang.NullPointerException原因:
at android.content.ContextWrapper.getClassLoader
(ContextWrapper.java:130)
InputStream is = getClass().getClassLoader().getResourceAsStream("helloworld.properties");中g(shù)etClass()和getClassLoader()都是什么意思呀.

getClass():取得當(dāng)前對象所屬的Class對象
getClassLoader():取得該Class對象的類裝載器
類裝載器負(fù)責(zé)從Java字符文件將字符流讀入內(nèi)存,并構(gòu)造Class類對象,在你說的問題哪里,通過它可以得到一個文件的輸入流

getClass :
public final Class getClass()
Returns the runtime class of an object. That Class object is the object that is locked by static synchronized methods of the represented class.
Returns:
the object of type Class that represents the runtime class of the object.
getClassLoader
public ClassLoader getClassLoader()
Returns the class loader for the class. Some implementations may use null to represent the bootstrap class loader. This method will return null in such implementations if this class was loaded by the bootstrap class loader.
If a security manager is present, and the caller′s class loader is not null and the caller′s class loader is not the same as or an ancestor of the class loader for the class whose class loader is requested, then this method calls the security manager′s checkPermission
method with a RuntimePermission("getClassLoader") permission to ensure it′s ok to access the class loader for the class.
If this object represents a primitive type or void, null is returned.
Returns:
the class loader that loaded the class or interface represented by this object.
Throws:
SecurityException - if a security manager exists and its checkPermission method denies access to the class loader for the class.
See Also:
ClassLoader, SecurityManager.checkPermission(java.security.Permission), RuntimePermission
Class.getClassLoader()的一個小陷阱:)

昨天我的code總在Integer.class.getClassLoader().getResource("*********");這一句拋出空指針異常,定位為getClassLoader()返回null,查了一下jdk的文檔,原來這里還有一個陷阱:

jdk中關(guān)于getClassLoader()的描述:
/**
* Returns the class loader for the class. Some implementations may use
* null to represent the bootstrap class loader. This method will return
* null in such implementations if this class was loaded by the bootstrap
* class loader.
*
* <p> If a security manager is present, and the caller's class loader is
* not null and the caller's class loader is not the same as or an ancestor of
* the class loader for the class whose class loader is requested, then
* this method calls the security manager's <code>checkPermission</code>
* method with a <code>RuntimePermission("getClassLoader")</code>
* permission to ensure it's ok to access the class loader for the class.
*
* <p>If this object
* represents a primitive type or void, null is returned.
.....
上面的英文可以用下面的話來理解:
裝載類的過程非常簡單:查找類所在位置,并將找到的Java類的字節(jié)碼裝入內(nèi)存,生成對應(yīng)的Class對象。Java的類裝載器專門用來實現(xiàn)這樣的過程,JVM并不止有一個類裝載器,事實上,如果你愿意的話,你可以讓JVM擁有無數(shù)個類裝載器,當(dāng)然這除了測試JVM外,我想不出還有其他的用途。你應(yīng)該已經(jīng)發(fā)現(xiàn)到了這樣一個問題,類裝載器自身也是一個類,它也需要被裝載到內(nèi)存中來,那么這些類裝載器由誰來裝載呢,總得有個根吧?沒錯,確實存在這樣的根,它就是神龍見首不見尾的Bootstrap ClassLoader. 為什么說它神龍見首不見尾呢,因為你根本無法在Java代碼中抓住哪怕是它的一點點的尾巴,盡管你能時時刻刻體會到它的存在,因為java的運行環(huán)境所需要的所有類庫,都由它來裝載,而它本身是C++寫的程序,可以獨立運行,可以說是JVM的運行起點,偉大吧。在Bootstrap完成它的任務(wù)后,會生成一個AppClassLoader(實際上之前系統(tǒng)還會使用擴(kuò)展類裝載器ExtClassLoader,它用于裝載Java運行環(huán)境擴(kuò)展包中的類),這個類裝載器才是我們經(jīng)常使用的,可以調(diào)用ClassLoader.getSystemClassLoader()來獲得,我們假定程序中沒有使用類裝載器相關(guān)操作設(shè)定或者自定義新的類裝載器,那么我們編寫的所有java類通通會由它來裝載,值得尊敬吧。AppClassLoader查找類的區(qū)域就是耳熟能詳?shù)腃lasspath,也是初學(xué)者必須跨過的門檻,有沒有靈光一閃的感覺,我們按照它的類查找范圍給它取名為類路徑類裝載器。還是先前假定的情況,當(dāng)Java中出現(xiàn)新的類,AppClassLoader首先在類傳遞給它的父類類裝載器,也就是Extion ClassLoader,詢問它是否能夠裝載該類,如果能,那AppClassLoader就不干這活了,同樣Extion ClassLoader在裝載時,也會先問問它的父類裝載器。我們可以看出類裝載器實際上是一個樹狀的結(jié)構(gòu)圖,每個類裝載器有自己的父親,類裝載器在裝載類時,總是先讓自己的父類裝載器裝載(多么尊敬長輩),如果父類裝載器無法裝載該類時,自己就會動手裝載,如果它也裝載不了,那么對不起,它會大喊一聲:Exception,class not found。有必要提一句,當(dāng)由直接使用類路徑裝載器裝載類失敗拋出的是NoClassDefFoundException異常。如果使用自定義的類裝載器loadClass方法或者ClassLoader的findSystemClass方法裝載類,如果你不去刻意改變,那么拋出的是ClassNotFoundException。
這里jdk告訴我們:如果一個類是通過bootstrap 載入的,那我們通過這個類去獲得classloader的話,有些jdk的實現(xiàn)是會返回一個null的,比如說我用 new Object().getClass().getClassLoader()的話,會返回一個null,這樣的話上面的代碼就會出現(xiàn)NullPointer異常.所以保險起見我們最好還是使用我們自己寫的類來獲取classloader("this.getClass().getClassLoader()“),這樣一來就不會有問題。

--------------------------------------------------------------------------------------------------------

ClassLoader詳解及用途(文件加載,類加載)
ClassLoader主要對類的請求提供服務(wù),當(dāng)JVM需要某類時,它根據(jù)名稱向ClassLoader要求這個類,然后由ClassLoader返回這個類的class對象。


1.1 幾個相關(guān)概念ClassLoader負(fù)責(zé)載入系統(tǒng)的所有Resources(Class,文件,來自網(wǎng)絡(luò)的字節(jié)流等),通過ClassLoader從而將資源載入JVM
每個class都有一個reference,指向自己的ClassLoader。Class.getClassLoader()
array的ClassLoader就是其元素的ClassLoader,若是基本數(shù)據(jù)類型,則這個array沒有ClassLoader


1.2 主要方法和工作過程Java1.1及從前版本中,ClassLoader主要方法:
Class loadClass( String name, boolean resolve ); ClassLoader.loadClass() 是 ClassLoader 的入口點
defineClass 方法是 ClassLoader 的主要訣竅。該方法接受由原始字節(jié)組成的數(shù)組并把它轉(zhuǎn)換成 Class 對象。原始數(shù)組包含如從文件系統(tǒng)或網(wǎng)絡(luò)裝入的數(shù)據(jù)。
findSystemClass 方法從本地文件系統(tǒng)裝入文件。它在本地文件系統(tǒng)中尋找類文件,如果存在,就使用 defineClass 將原始字節(jié)轉(zhuǎn)換成 Class 對象,以將該文件轉(zhuǎn)換成類。當(dāng)運行 Java 應(yīng)用程序時,這是 JVM 正常裝入類的缺省機(jī)制。
resolveClass可以不完全地(不帶解析)裝入類,也可以完全地(帶解析)裝入類。當(dāng)編寫我們自己的 loadClass 時,可以調(diào)用 resolveClass,這取決于 loadClass 的 resolve 參數(shù)的值
findLoadedClass 充當(dāng)一個緩存:當(dāng)請求 loadClass 裝入類時,它調(diào)用該方法來查看 ClassLoader 是否已裝入這個類,這樣可以避免重新裝入已存在類所造成的麻煩。應(yīng)首先調(diào)用該方法

一般load方法過程如下:
調(diào)用 findLoadedClass 來查看是否存在已裝入的類。
如果沒有,那么采用某種特殊的神奇方式來獲取原始字節(jié)。(通過IO從文件系統(tǒng),來自網(wǎng)絡(luò)的字節(jié)流等)
如果已有原始字節(jié),調(diào)用 defineClass 將它們轉(zhuǎn)換成 Class 對象。
如果沒有原始字節(jié),然后調(diào)用 findSystemClass 查看是否從本地文件系統(tǒng)獲取類。
如果 resolve 參數(shù)是 true,那么調(diào)用 resolveClass 解析 Class 對象。
如果還沒有類,返回 ClassNotFoundException。
否則,將類返回給調(diào)用程序。

1.3 委托模型自從JDK1.2以后,ClassLoader做了改進(jìn),使用了委托模型,所有系統(tǒng)中的ClassLoader組成一棵樹,ClassLoader在載入類庫時先讓Parent尋找,Parent找不到才自己找。
JVM在運行時會產(chǎn)生三個ClassLoader,Bootstrap ClassLoader、Extension ClassLoader和App ClassLoader。其中,Bootstrap ClassLoader是用C++編寫的,在Java中看不到它,是null。它用來加載核心類庫,就是在lib下的類庫,Extension ClassLoader加載lib/ext下的類庫,App ClassLoader加載Classpath里的類庫,三者的關(guān)系為:App ClassLoader的Parent是Extension ClassLoader,而Extension ClassLoader的Parent為Bootstrap ClassLoader。加載一個類時,首先BootStrap進(jìn)行尋找,找不到再由Extension ClassLoader尋找,最后才是App ClassLoader。
將ClassLoader設(shè)計成委托模型的一個重要原因是出于安全考慮,比如在Applet中,如果編寫了一個java.lang.String類并具有破壞性。假如不采用這種委托機(jī)制,就會將這個具有破壞性的String加載到了用戶機(jī)器上,導(dǎo)致破壞用戶安全。但采用這種委托機(jī)制則不會出現(xiàn)這種情況。因為要加載java.lang.String類時,系統(tǒng)最終會由Bootstrap進(jìn)行加載,這個具有破壞性的String永遠(yuǎn)沒有機(jī)會加載。
委托模型還帶來了一些問題,在某些情況下會產(chǎn)生混淆,如下是Tomcat的ClassLoader結(jié)構(gòu)圖:
Bootstrap
|
System
|
Common
/
Catalina Shared
/
Webapp1 Webapp2 ...


由 Common 類裝入器裝入的類決不能(根據(jù)名稱)直接訪問由 Web 應(yīng)用程序裝入的類。使這些類聯(lián)系在一起的唯一方法是通過使用這兩個類集都可見的接口。在這個例子中,就是包含由 Java servlet 實現(xiàn)的 javax.servlet.Servlet。
如果在lib或者lib/ext等類庫有與應(yīng)用中同樣的類,那么應(yīng)用中的類將無法被載入。通常在jdk新版本出現(xiàn)有類庫移動時會出現(xiàn)問題,例如最初我們使用自己的xml解析器,而在jdk1.4中xml解析器變成標(biāo)準(zhǔn)類庫,load的優(yōu)先級也高于我們自己的xml解析器,我們自己的xml解析器永遠(yuǎn)無法找到,將可能導(dǎo)致我們的應(yīng)用無法運行。
相同的類,不同的ClassLoader,將導(dǎo)致ClassCastException異常

1.4 線程中的ClassLoader每個運行中的線程都有一個成員contextClassLoader,用來在運行時動態(tài)地載入其它類,可以使用方法Thread.currentThread().setContextClassLoader(...);更改當(dāng)前線程的contextClassLoader,來改變其載入類的行為;也可以通過方法Thread.currentThread().getContextClassLoader()來獲得當(dāng)前線程的ClassLoader。
實際上,在Java應(yīng)用中所有程序都運行在線程里,如果在程序中沒有手工設(shè)置過ClassLoader,對于一般的java類如下兩種方法獲得的ClassLoader通常都是同一個
this.getClass.getClassLoader();
Thread.currentThread().getContextClassLoader();
方法一得到的Classloader是靜態(tài)的,表明類的載入者是誰;方法二得到的Classloader是動態(tài)的,誰執(zhí)行(某個線程),就是那個執(zhí)行者的Classloader。對于單例模式的類,靜態(tài)類等,載入一次后,這個實例會被很多程序(線程)調(diào)用,對于這些類,載入的Classloader和執(zhí)行線程的Classloader通常都不同。

1.5 Web應(yīng)用中的ClassLoader回到上面的例子,在Tomcat里,WebApp的ClassLoader的工作原理有點不同,它先試圖自己載入類(在ContextPath/WEB-INF/...中載入類),如果無法載入,再請求父ClassLoader完成。
由此可得:
對于WEB APP線程,它的contextClassLoader是WebAppClassLoader
對于Tomcat Server線程,它的contextClassLoader是CatalinaClassLoader

1.6 獲得ClassLoader的幾種方法可以通過如下3種方法得到ClassLoader
this.getClass.getClassLoader(); // 使用當(dāng)前類的ClassLoader
Thread.currentThread().getContextClassLoader(); // 使用當(dāng)前線程的ClassLoader
ClassLoader.getSystemClassLoader(); // 使用系統(tǒng)ClassLoader,即系統(tǒng)的入口點所使用的ClassLoader。(注意,system ClassLoader與根ClassLoader并不一樣。JVM下system ClassLoader通常為App ClassLoader)

1.7 幾種擴(kuò)展應(yīng)用用戶定制自己的ClassLoader可以實現(xiàn)以下的一些應(yīng)用安全性。

類進(jìn)入JVM之前先經(jīng)過ClassLoader,所以可以在這邊檢查是否有正確的數(shù)字簽名等加密。java字節(jié)碼很容易被反編譯,通過定制ClassLoader使得字節(jié)碼先加密防止別人下載后反編譯,這里的ClassLoader相當(dāng)于一個動態(tài)的解碼器歸檔。可能為了節(jié)省網(wǎng)絡(luò)資源,對自己的代碼做一些特殊的歸檔,然后用定制的ClassLoader來解檔自展開程序。把java應(yīng)用程序編譯成單個可執(zhí)行類文件,這個文件包含壓縮的和加密的類文件數(shù)據(jù),同時有一個固定的ClassLoader,當(dāng)程序運行時它在內(nèi)存中完全自行解開,無需先安裝動態(tài)生成。可以生成應(yīng)用其他還未生成類的類,實時創(chuàng)建整個類并可在任何時刻引入JVM

2.0 資源載入
所有資源都通過ClassLoader載入到JVM里,那么在載入資源時當(dāng)然可以使用ClassLoader,只是對于不同的資源還可以使用一些別的方式載入,例如對于類可以直接new,對于文件可以直接做IO等。 2.1 載入類的幾種方法假設(shè)有類A和類B,A在方法amethod里需要實例化B,可能的方法有3種。對于載入類的情況,用戶需要知道B類的完整名字(包括包名,例如"com.rain.B")
1. 使用Class靜態(tài)方法 Class.forName
Class cls = Class.forName("com.rain.B");
B b = (B)cls.newInstance();

2. 使用ClassLoader
/* Step 1. Get ClassLoader */
ClassLoader cl; // 如何獲得ClassLoader參考1.6
/* Step 2. Load the class */
Class cls = cl.loadClass("com.rain.B"); // 使用第一步得到的ClassLoader來載入B
/* Step 3. new instance */
B b = (B)cls.newInstance(); // 有B的類得到一個B的實例

3. 直接new
B b = new B();

2.2 文件載入(例如配置文件等)假設(shè)在com.rain.A類里想讀取文件夾 /com/rain/config 里的文件sys.properties,讀取文件可以通過絕對路徑或相對路徑,絕對路徑很簡單,在Windows下以盤號開始,在Unix下以"/"開始
對于相對路徑,其相對值是相對于ClassLoader的,因為ClassLoader是一棵樹,所以這個相對路徑和ClassLoader樹上的任何一個ClassLoader相對比較后可以找到文件,那么文件就可以找到,當(dāng)然,讀取文件也使用委托模型

1. 直接IO
/**

* 假設(shè)當(dāng)前位置是 "C:/test",通過執(zhí)行如下命令來運行A "java com.rain.A"
* 1. 在程序里可以使用絕對路徑,Windows下的絕對路徑以盤號開始,Unix下以"/"開始
* 2. 也可以使用相對路徑,相對路徑前面沒有"/"
* 因為我們在 "C:/test" 目錄下執(zhí)行程序,程序入口點是"C:/test",相對路徑就
* 是 "com/rain/config/sys.properties"
* (例子中,當(dāng)前程序的ClassLoader是App ClassLoader,system ClassLoader = 當(dāng)前的
* 程序的ClassLoader,入口點是"C:/test")
* 對于ClassLoader樹,如果文件在jdk lib下,如果文件在jdk lib/ext下,如果文件在環(huán)境變量里,
* 都可以通過相對路徑"sys.properties"找到,lib下的文件最先被找到
*/
File f = new File("C:/test/com/rain/config/sys.properties"); // 使用絕對路徑
//File f = new File("com/rain/config/sys.properties"); // 使用相對路徑
InputStream is = new FileInputStream(f);
如果是配置文件,可以通過java.util.Properties.load(is)將內(nèi)容讀到Properties里,Properties默認(rèn)認(rèn)為is的編碼是ISO-8859-1,如果配置文件是非英文的,可能出現(xiàn)亂碼問題。

2. 使用ClassLoader
/**
* 因為有3種方法得到ClassLoader,對應(yīng)有如下3種方法讀取文件
* 使用的路徑是相對于這個ClassLoader的那個點的相對路徑,此處只能使用相對路徑
*/
InputStream is = null;
is = this.getClass().getClassLoader().getResourceAsStream(
"com/rain/config/sys.properties"); //方法1
//is = Thread.currentThread().getContextClassLoader().getResourceAsStream(
"com/rain/config/sys.properties"); //方法2
//is = ClassLoader.getSystemResourceAsStream("com/rain/config/sys.properties"); //方法3
如果是配置文件,可以通過java.util.Properties.load(is)將內(nèi)容讀到Properties里,這里要注意編碼問題。

3. 使用ResourceBundle
ResourceBundle bundle = ResourceBundle.getBoundle("com.rain.config.sys");
這種用法通常用來載入用戶的配置文件,關(guān)于ResourceBunlde更詳細(xì)的用法請參考其他文檔
總結(jié):有如下3種途徑來載入文件
1. 絕對路徑 ---> IO
2. 相對路徑 ---> IO
---> ClassLoade
3. 資源文件 ---> ResourceBundle


2.3 如何在web應(yīng)用里載入資源在web應(yīng)用里當(dāng)然也可以使用ClassLoader來載入資源,但更常用的情況是使用ServletContext,如下是web目錄結(jié)構(gòu)
ContextRoot
|- JSP、HTML、Image等各種文件
|- [WEB-INF]
|- web.xml
|- [lib] Web用到的JAR文件
|- [classes] 類文件
用戶程序通常在classes目錄下,如果想讀取classes目錄里的文件,可以使用ClassLoader,如果想讀取其他的文件,一般使用ServletContext.getResource()
如果使用ServletContext.getResource(path)方法,路徑必須以"/"開始,路徑被解釋成相對于ContextRoot的路徑,此處載入文件的方法和ClassLoader不同,舉例"/WEB-INF/web.xml","/download/WebExAgent.rar"

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Ken Wu's Blog ? java類加載器體系結(jié)構(gòu)(含hotswap原理)
JVM --- 結(jié)構(gòu)體系
java資源獲取分析
關(guān)于getClass().getClassLoader()
JAVA虛擬機(jī)加載類的方式解析
JVM系列(二):JVM中類加載器相關(guān)知識筆記
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服