API 文檔詳解
ClassLoader是一個(gè)類加載器對(duì)象舷夺,負(fù)責(zé)去加載類。ClassLoader是一個(gè)抽象對(duì)象售貌。給定了一個(gè)類的“二進(jìn)制名稱”给猾,一個(gè)類加載器需要嘗試去定位或者生成一個(gè)數(shù)據(jù),該數(shù)據(jù)構(gòu)成了一個(gè)定義的類颂跨。一個(gè)典型的策略就是轉(zhuǎn)換名字(即敢伸,二進(jìn)制名字)成一個(gè)文件名,然后從文件系統(tǒng)讀取這個(gè)文件名包含的“字節(jié)碼文件”恒削。
注意池颈,這里有兩種方式來(lái)通過(guò)一個(gè)“二進(jìn)制名稱”來(lái)加載一個(gè)類:
① 定位
也就是說(shuō),表示這個(gè)類的數(shù)據(jù)已經(jīng)存在了钓丰,類加載器去定位到這個(gè)存儲(chǔ)的數(shù)據(jù)進(jìn)行加載即可躯砰。比如,java.lang.String就是在rt.jar中存儲(chǔ)的了携丁,可以直接定位到琢歇。
② 生成
一些在java代碼中動(dòng)態(tài)生成的類,而這些類的數(shù)據(jù)就是在運(yùn)行期時(shí)由類加載器去生成的梦鉴。比如李茫,動(dòng)態(tài)代理。
“二進(jìn)制名稱”:任意一個(gè)類名被提供作為ClassLoader方法的字符串參數(shù)尚揣,這個(gè)字符串形式的類名字必須是一個(gè)二進(jìn)制名稱涌矢,這個(gè)二進(jìn)制名字是由java語(yǔ)言規(guī)范定義的。
有效類名字的示例包括:
"java.lang.String"
"javax.swing.JSpinner$DefaultEditor"
"java.security.KeyStore$Builder$FileBuilder$1"
"java.net.URLClassLoader$3$1"
"java.security.KeyStore$Builder$FileBuilder$1"
:KeyStore里面的內(nèi)部類Builder快骗,Builder里面的內(nèi)部類FileBuilder娜庇,F(xiàn)ileBuilder里面的“第一個(gè)”匿名內(nèi)部類。
每個(gè)Class對(duì)象包含了一個(gè)定義它的ClassLoader的引用(『Class#getClassLoader()』返回一個(gè)指向ClassLoader的引用)方篮。
數(shù)組類的Class對(duì)象不是由類加載器創(chuàng)建的名秀,而是Java虛擬機(jī)在運(yùn)行時(shí)根據(jù)需要所自動(dòng)創(chuàng)建(注意,只有數(shù)組類是特殊的藕溅,其他類對(duì)象都是通過(guò)類加載器來(lái)創(chuàng)建的)匕得。數(shù)組類的類加載器(即,『ArrayClass#getClassLoader()』),同它的元素類型通過(guò)『Class#getClassLoader()』返回的類加載器是一樣的汁掠;如果元素類型是一個(gè)原生類型略吨,那么數(shù)組類沒(méi)有類加載器(即,『Class#getClassLoader()』返回null)考阱。
public class MyTest15 {
public static void main(String[] args) {
String[][] strings = new String[2][];
System.out.println(strings.getClass().getClassLoader());
System.out.println("=============================");
MyTest15[] myTest15s = new MyTest15[2];
System.out.println(myTest15s.getClass().getClassLoader());
System.out.println("=============================");
int[] ints = new int[2];
System.out.println(ints.getClass().getClassLoader());
}
}
# 控制臺(tái)
null
=============================
sum.misc.Launcher$AppClassLoader@18b4aac2
=============================
null
對(duì)于數(shù)組類而言翠忠,情況就有所不同,數(shù)組類本身不通過(guò)類加載器創(chuàng)建乞榨,它是由Java虛擬機(jī)在運(yùn)行時(shí)直接創(chuàng)建的(‘?dāng)?shù)組’的父類是’Object’)秽之。但數(shù)組類與類加載器仍然有很密切的關(guān)系,因?yàn)閿?shù)組類的元素類型(Element Type吃既,指的是數(shù)組去掉所有維度的類型)最終是要靠類加載器去創(chuàng)建考榨。
如果數(shù)組的組件類型(Component Type,指的是數(shù)組去掉一個(gè)維度的類型)是引用類型鹦倚,那就遞歸采用本節(jié)中定義的加載過(guò)程去加載這個(gè)組件類型河质,數(shù)組C將在加載該組件類型的類加載器的類名稱空間上被標(biāo)識(shí)。
如果數(shù)組的組件類型不是引用類型(例如int[]數(shù)組)申鱼,Java虛擬機(jī)將會(huì)把數(shù)組C標(biāo)記為與引導(dǎo)類加載器關(guān)聯(lián)愤诱。
所以,這里捐友。strings.getClass().getClassLoader() 和 ints.getClass().getClassLoader() 都返回 null淫半,標(biāo)簽其都是通過(guò)“引導(dǎo)類加載器”加載的。
應(yīng)用實(shí)現(xiàn)ClassLoader的子類為了擴(kuò)展Java虛擬機(jī)動(dòng)態(tài)加載類的方式匣砖。
??這個(gè)句話說(shuō)明了科吭,自定義類加載器的核心用途。
類加載器典型情況下是可以被安全管理器所使用來(lái)去指示的一些安全域問(wèn)題猴鲫。
也就是对人,類加載器本身都會(huì)伴隨著一個(gè)安全管理器的概念,來(lái)去確保類加載的過(guò)程一定是安全的拂共。
ClassLoader類使用一個(gè)委托模型去查詢類和資源牺弄。ClassLoader的每一個(gè)實(shí)例有一個(gè)相關(guān)的父加載器。當(dāng)請(qǐng)求去尋找一個(gè)類或資源時(shí)宜狐,一個(gè)ClassLoader實(shí)例會(huì)將類或資源的查詢委托給它的父加載器在它自己去嘗試去尋找類或資源之前势告。虛擬機(jī)“內(nèi)建”的類加載器叫做“啟動(dòng)類加載器”,它沒(méi)有一個(gè)父加載器抚恒,但是它作為一個(gè)ClassLoader實(shí)例的父加載器咱台。
支持并發(fā)加載類的類加載器被稱為并行的類加載器,并且被要求通過(guò)『ClassLoader.registerAsParallelCapable』方法去注冊(cè)它們自己當(dāng)它們的類初始化時(shí)俭驮。注意回溺,ClassLoader默認(rèn)被注冊(cè)為有并行能力的。然而,它們的子類仍然需要去注冊(cè)它們自己遗遵,如果它們(即萍恕,ClassLoader的子類)是并行加載的。
在委托模式并不是嚴(yán)格的層次化的環(huán)境下(即瓮恭,和JVM內(nèi)建的委托模型不一致或沖突的情況下)雄坪,類加載器是需要并行能力的,否則類加載將導(dǎo)致死鎖屯蹦,因?yàn)榧虞d鎖在類加載過(guò)程中被持續(xù)持有。(見(jiàn)『ClassLoader#loadClass』方法)
通常地绳姨,Java虛擬機(jī)以平臺(tái)相關(guān)的方式(即登澜,不是獨(dú)立于平臺(tái)的)從本地文件系統(tǒng)加載類。比如飘庄,在UNIX系統(tǒng)下脑蠕,虛擬機(jī)通過(guò)環(huán)境變量“CLASSPAH”定義的目錄中加載類。
然而跪削,一些類可能不是起源于一個(gè)文件谴仙;它們可能源于其他來(lái)源,比如網(wǎng)絡(luò)碾盐,或者它們能被一個(gè)應(yīng)用構(gòu)造(比如晃跺,動(dòng)態(tài)代理)『辆粒『defineClass(String, byte[], int, int)』方法會(huì)將一個(gè)字節(jié)數(shù)組轉(zhuǎn)換為一個(gè)Class類實(shí)例掀虎。這個(gè)新定義的類的實(shí)例能使用『Class#newInstance』方法來(lái)創(chuàng)建。
通過(guò)一個(gè)類加載器創(chuàng)建的對(duì)象的方法和構(gòu)造方法可能會(huì)引用到其他類付枫。為了確定所引用的類烹玉,Java虛擬機(jī)調(diào)用最初創(chuàng)建該類的類加載器的『loadClass』方法。(即阐滩,使用這個(gè)類的定義類加載器去加載所引用的類)
真正負(fù)責(zé)成功加載這個(gè)類的加載器二打,我們稱之為“定義類加載器”。
接受類加載請(qǐng)求掂榔,通過(guò)調(diào)用loadClass來(lái)開(kāi)啟類的加載過(guò)程的加載器被稱為初始類加載器继效。
比如,一個(gè)應(yīng)用可以創(chuàng)建一個(gè)網(wǎng)絡(luò)‘類加載器’衅疙,以從一個(gè)服務(wù)端下載類莲趣。簡(jiǎn)單的代碼可能看起來(lái)像:
ClassLoader loader = new NetworkClassLoader(host, port);
Object main = loader.loadClass("Main", true).newInstance();
. . .
網(wǎng)絡(luò)類加載器的子類必須定義『findClass』和『loadClassData』方法去從網(wǎng)絡(luò)加載一個(gè)類。一旦它已經(jīng)下載了組成類的字節(jié)饱溢,它需要使用『defineClass』方法去創(chuàng)建一個(gè)類實(shí)例喧伞。一個(gè)簡(jiǎn)單的實(shí)現(xiàn):
class NetworkClassLoader extends ClassLoader {
String host;
int port;
public Class findClass(String name) {
byte[] b = loadClassData(name);
return defineClass(name, b, 0, b.length);
}
private byte[] loadClassData(String name) {
// load the class data from the connection
. . .
}
}
重要方法講解
- Class#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}
* method with a {@code RuntimePermission("getClassLoader")}
* 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.
*
* @return the class loader that loaded the class or interface
* represented by this object.
* @throws SecurityException
* if a security manager exists and its
* {@code checkPermission} method denies
* access to the class loader for the class.
* @see java.lang.ClassLoader
* @see SecurityManager#checkPermission
* @see java.lang.RuntimePermission
*/
@CallerSensitive
public ClassLoader getClassLoader() {
ClassLoader cl = getClassLoader0();
if (cl == null)
return null;
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
ClassLoader.checkClassLoaderPermission(cl, Reflection.getCallerClass());
}
return cl;
}
返回真實(shí)加載這個(gè)類/接口的加載器。一些實(shí)現(xiàn)可能會(huì)返回null表示“啟動(dòng)類加載器”。這個(gè)方法就是這樣的實(shí)現(xiàn)潘鲫,它將會(huì)返回null翁逞,如果類是被“啟動(dòng)類加載器”加載的話。
如果這里使用了安全管理器的話溉仑,并且”調(diào)用者的類加載器“或者”請(qǐng)求加載這個(gè)類的類加載器的祖先類加載器“不為空挖函。那么這個(gè)方法就會(huì)去調(diào)用安全管理器的『checkPermission()』方法來(lái)去看是否能訪問(wèn)到這個(gè)類的加載器(定義類加載器)。
如果這個(gè)對(duì)象代表了一個(gè)原生類型或者void浊竟,那么會(huì)返回null怨喘。
- getSystemClassLoader()
/**
* Returns the system class loader for delegation. This is the default
* delegation parent for new <tt>ClassLoader</tt> instances, and is
* typically the class loader used to start the application.
*
* <p> This method is first invoked early in the runtime's startup
* sequence, at which point it creates the system class loader and sets it
* as the context class loader of the invoking <tt>Thread</tt>.
*
* <p> The default system class loader is an implementation-dependent
* instance of this class.
*
* <p> If the system property "<tt>java.system.class.loader</tt>" is defined
* when this method is first invoked then the value of that property is
* taken to be the name of a class that will be returned as the system
* class loader. The class is loaded using the default system class loader
* and must define a public constructor that takes a single parameter of
* type <tt>ClassLoader</tt> which is used as the delegation parent. An
* instance is then created using this constructor with the default system
* class loader as the parameter. The resulting class loader is defined
* to be the system class loader.
*
* <p> If a security manager is present, and the invoker's class loader is
* not <tt>null</tt> and the invoker's class loader is not the same as or
* an ancestor of the system class loader, then this method invokes the
* security manager's {@link
* SecurityManager#checkPermission(java.security.Permission)
* <tt>checkPermission</tt>} method with a {@link
* RuntimePermission#RuntimePermission(String)
* <tt>RuntimePermission("getClassLoader")</tt>} permission to verify
* access to the system class loader. If not, a
* <tt>SecurityException</tt> will be thrown. </p>
*
* @return The system <tt>ClassLoader</tt> for delegation, or
* <tt>null</tt> if none
*
* @throws SecurityException
* If a security manager exists and its <tt>checkPermission</tt>
* method doesn't allow access to the system class loader.
*
* @throws IllegalStateException
* If invoked recursively during the construction of the class
* loader specified by the "<tt>java.system.class.loader</tt>"
* property.
*
* @throws Error
* If the system property "<tt>java.system.class.loader</tt>"
* is defined but the named class could not be loaded, the
* provider class does not define the required constructor, or an
* exception is thrown by that constructor when it is invoked. The
* underlying cause of the error can be retrieved via the
* {@link Throwable#getCause()} method.
*
* @revised 1.4
*/
@CallerSensitive
public static ClassLoader getSystemClassLoader() {
initSystemClassLoader();
if (scl == null) {
return null;
}
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkClassLoaderPermission(scl, Reflection.getCallerClass());
}
return scl;
}
返回一個(gè)基于委托模式的系統(tǒng)類加載器。它是新的類加載器默認(rèn)的委托父類實(shí)例振定,并且它是用于啟動(dòng)應(yīng)用的典型類加載器必怜。
首先在運(yùn)行時(shí)的啟動(dòng)序列中調(diào)用此方法,此時(shí)它會(huì)創(chuàng)建系統(tǒng)類加載器并將其設(shè)置為調(diào)用線程的上下文類加載器后频。
默認(rèn)的系統(tǒng)類加載器是與這個(gè)實(shí)現(xiàn)相關(guān)的一個(gè)實(shí)例梳庆。
如果當(dāng)這個(gè)方法第一次被調(diào)用的時(shí)候,系統(tǒng)屬性”java.system.class.loader”是被定義的卑惜,那么這個(gè)屬性的值就會(huì)被作為系統(tǒng)類加載器的名字膏执。而這個(gè)類是使用默認(rèn)的系統(tǒng)類加載器來(lái)去加載的,并且必須定義一個(gè)public的接收單個(gè)類型為ClassLoader參數(shù)的構(gòu)造方法露久,同時(shí)這個(gè)傳入的ClassLoader會(huì)作為委托的雙親更米。一個(gè)實(shí)例接下來(lái)會(huì)被創(chuàng)建通過(guò)使用這個(gè)構(gòu)造方法,同時(shí)會(huì)將默認(rèn)的系統(tǒng)類加載器作為參數(shù)傳入抱环,而所生成的類就會(huì)被定義成’系統(tǒng)類加載器’壳快。
也就是說(shuō),默認(rèn)的情況下’系統(tǒng)類加載器’就是’AppClassLoader’镇草,但是對(duì)于JDK來(lái)說(shuō)眶痰,如果提供了”java.system.class.loader"這個(gè)系統(tǒng)屬性,我們可以通過(guò)這個(gè)系統(tǒng)屬性來(lái)去顯示的修改“系統(tǒng)類加載器”梯啤,也就是說(shuō)讓“系統(tǒng)類加載器”不再是“AppClassLoader”竖伯,而是我們自定義的某個(gè)ClassLoader。
- ClassLoader parent
// The parent class loader for delegation
// Note: VM hardcoded the offset of this field, thus all new fields
// must be added *after* it.
private final ClassLoader parent;
虛擬機(jī)會(huì)硬編碼這個(gè)字段的偏移量因宇,因此所有新的字段必須在它的后面七婴。
- Thread#getContextClassLoader()()
/**
* Returns the context ClassLoader for this Thread. The context
* ClassLoader is provided by the creator of the thread for use
* by code running in this thread when loading classes and resources.
* If not {@linkplain #setContextClassLoader set}, the default is the
* ClassLoader context of the parent Thread. The context ClassLoader of the
* primordial thread is typically set to the class loader used to load the
* application.
*
* <p>If a security manager is present, and the invoker's class loader is not
* {@code null} and is not the same as or an ancestor of the context class
* loader, then this method invokes the security manager's {@link
* SecurityManager#checkPermission(java.security.Permission) checkPermission}
* method with a {@link RuntimePermission RuntimePermission}{@code
* ("getClassLoader")} permission to verify that retrieval of the context
* class loader is permitted.
*
* @return the context ClassLoader for this Thread, or {@code null}
* indicating the system class loader (or, failing that, the
* bootstrap class loader)
*
* @throws SecurityException
* if the current thread cannot get the context ClassLoader
*
* @since 1.2
*/
@CallerSensitive
public ClassLoader getContextClassLoader() {
if (contextClassLoader == null)
return null;
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
ClassLoader.checkClassLoaderPermission(contextClassLoader,
Reflection.getCallerClass());
}
return contextClassLoader;
}
返回這個(gè)線程的上下文類加載器。線程上下文類加載器是通過(guò)線程的創(chuàng)建者本身所提供的察滑,用于在運(yùn)行線程中代碼的時(shí)候去加載類與資源打厘。如果沒(méi)有設(shè)置『setContextClassLoader』,那么默認(rèn)的上下文類加載器就是父線程的上下文類加載器贺辰。一個(gè)原始線程的上下文類加載器典型情況下會(huì)被設(shè)置為用于加載應(yīng)用的類加載器(也就是“系統(tǒng)類加載器”)户盯。
- getResource(String name)
public URL getResource(String name) {
URL url;
if (parent != null) {
url = parent.getResource(name);
} else {
url = getBootstrapResource(name);
}
if (url == null) {
url = findResource(name);
}
return url;
}
尋找給定名字的所有資源嵌施。一個(gè)資源是一些能被類代碼訪問(wèn)的數(shù)據(jù)(如,圖片莽鸭、音頻吗伤、文本,等)硫眨,它(即足淆,數(shù)據(jù))是以獨(dú)立于代碼位置的方式進(jìn)行訪問(wèn)的。
一個(gè)資源的名稱是一個(gè)以“/”來(lái)去分割的路徑名稱來(lái)標(biāo)識(shí)的資源礁阁。
- ClassLoader() 構(gòu)造方法
使用通過(guò)『getSystemClassLoader()』方法返回的類加載器來(lái)創(chuàng)建一個(gè)新的類加載器巧号。
getSystemClassLoader()作為它的父類加載器。
也就是說(shuō)氮兵,默認(rèn)情況下裂逐,當(dāng)使用無(wú)參構(gòu)造方法創(chuàng)建新的類加載器時(shí)我們所自定義的類加載器的父類加載器就是系統(tǒng)類加載器。
- findClass(String name)
/**
* Finds the class with the specified <a href="#name">binary name</a>.
* This method should be overridden by class loader implementations that
* follow the delegation model for loading classes, and will be invoked by
* the {@link #loadClass <tt>loadClass</tt>} method after checking the
* parent class loader for the requested class. The default implementation
* throws a <tt>ClassNotFoundException</tt>.
*
* @param name
* The <a href="#name">binary name</a> of the class
*
* @return The resulting <tt>Class</tt> object
*
* @throws ClassNotFoundException
* If the class could not be found
*
* @since 1.2
*/
protected Class<?> findClass(String name) throws ClassNotFoundException {
throw new ClassNotFoundException(name);
}
尋找指定“二進(jìn)制名字”的類泣栈。這個(gè)方法應(yīng)該被類加載器的實(shí)現(xiàn)所重寫(xiě),這個(gè)方法必須被類加載器所實(shí)現(xiàn)弥姻,且該類加載器應(yīng)該遵循委托模型來(lái)去加載指定的類南片,這個(gè)方法會(huì)在父類加載器檢測(cè)完請(qǐng)求類的加載后被『loadClass』方法所調(diào)用。該方法的默認(rèn)實(shí)現(xiàn)會(huì)拋出一個(gè)“ClassNotFoundException”異常庭敦。
- defineClass(String name, byte[] b, int off, int len)
/**
* Converts an array of bytes into an instance of class <tt>Class</tt>.
* Before the <tt>Class</tt> can be used it must be resolved.
*
* <p> This method assigns a default {@link java.security.ProtectionDomain
* <tt>ProtectionDomain</tt>} to the newly defined class. The
* <tt>ProtectionDomain</tt> is effectively granted the same set of
* permissions returned when {@link
* java.security.Policy#getPermissions(java.security.CodeSource)
* <tt>Policy.getPolicy().getPermissions(new CodeSource(null, null))</tt>}
* is invoked. The default domain is created on the first invocation of
* {@link #defineClass(String, byte[], int, int) <tt>defineClass</tt>},
* and re-used on subsequent invocations.
*
* <p> To assign a specific <tt>ProtectionDomain</tt> to the class, use
* the {@link #defineClass(String, byte[], int, int,
* java.security.ProtectionDomain) <tt>defineClass</tt>} method that takes a
* <tt>ProtectionDomain</tt> as one of its arguments. </p>
*
* @param name
* The expected <a href="#name">binary name</a> of the class, or
* <tt>null</tt> if not known
*
* @param b
* The bytes that make up the class data. The bytes in positions
* <tt>off</tt> through <tt>off+len-1</tt> should have the format
* of a valid class file as defined by
* <cite>The Java™ Virtual Machine Specification</cite>.
*
* @param off
* The start offset in <tt>b</tt> of the class data
*
* @param len
* The length of the class data
*
* @return The <tt>Class</tt> object that was created from the specified
* class data.
*
* @throws ClassFormatError
* If the data did not contain a valid class
*
* @throws IndexOutOfBoundsException
* If either <tt>off</tt> or <tt>len</tt> is negative, or if
* <tt>off+len</tt> is greater than <tt>b.length</tt>.
*
* @throws SecurityException
* If an attempt is made to add this class to a package that
* contains classes that were signed by a different set of
* certificates than this class (which is unsigned), or if
* <tt>name</tt> begins with "<tt>java.</tt>".
*
* @see #loadClass(String, boolean)
* @see #resolveClass(Class)
* @see java.security.CodeSource
* @see java.security.SecureClassLoader
*
* @since 1.1
*/
protected final Class<?> defineClass(String name, byte[] b, int off, int len)
throws ClassFormatError
{
return defineClass(name, b, off, len, null);
}
將一個(gè)字節(jié)數(shù)組轉(zhuǎn)換成一個(gè)Class類的實(shí)例疼进。在Class能被使用之前它必須要被解析(該“解析”就是類加載過(guò)程中的“連接”的第三階段)。
這個(gè)方法會(huì)分配一個(gè)默認(rèn)的ProtectionDomain給新定義的類(ProtectionDomain是為了確保我們所返回來(lái)的Class的一切信息都是正確的秧廉。比如伞广,我們?nèi)ゼ虞d一個(gè)類,我們要確保這個(gè)類跟它相同包下其他的類用相同的包名疼电。)嚼锄。這個(gè)默認(rèn)的domain是在第一次調(diào)用『defineClass』的時(shí)候被創(chuàng)建,并且在隨后的調(diào)用當(dāng)中可以被復(fù)用蔽豺。
要想給class指定一個(gè)特定的ProtectionDomain区丑,可以使用defineClass的另一個(gè)重載方法(『protected final Class<?> defineClass(String name, byte[] b, int off, int len, ProtectionDomain protectionDomain)』)
SecurityException(運(yùn)行時(shí)異常):如果嘗試做出添加這個(gè)類到一個(gè)包中,該包中包含的類使用了不同這個(gè)類的證書(shū)簽名修陡;或者沧侥,如果二進(jìn)制的名稱以“java.”開(kāi)頭。
- loadClass(String name)
/**
* Loads the class with the specified <a href="#name">binary name</a>.
* This method searches for classes in the same manner as the {@link
* #loadClass(String, boolean)} method. It is invoked by the Java virtual
* machine to resolve class references. Invoking this method is equivalent
* to invoking {@link #loadClass(String, boolean) <tt>loadClass(name,
* false)</tt>}.
*
* @param name
* The <a href="#name">binary name</a> of the class
*
* @return The resulting <tt>Class</tt> object
*
* @throws ClassNotFoundException
* If the class was not found
*/
public Class<?> loadClass(String name) throws ClassNotFoundException {
return loadClass(name, false);
}
加載使用指定二進(jìn)制名字的類魄鸦。這個(gè)方法搜索類的方式是與『loadClass(String, boolean)』方法一樣的宴杀。
- loadClass(String name, boolean resolve)
/**
* Loads the class with the specified <a href="#name">binary name</a>. The
* default implementation of this method searches for classes in the
* following order:
*
* <ol>
*
* <li><p> Invoke {@link #findLoadedClass(String)} to check if the class
* has already been loaded. </p></li>
*
* <li><p> Invoke the {@link #loadClass(String) <tt>loadClass</tt>} method
* on the parent class loader. If the parent is <tt>null</tt> the class
* loader built-in to the virtual machine is used, instead. </p></li>
*
* <li><p> Invoke the {@link #findClass(String)} method to find the
* class. </p></li>
*
* </ol>
*
* <p> If the class was found using the above steps, and the
* <tt>resolve</tt> flag is true, this method will then invoke the {@link
* #resolveClass(Class)} method on the resulting <tt>Class</tt> object.
*
* <p> Subclasses of <tt>ClassLoader</tt> are encouraged to override {@link
* #findClass(String)}, rather than this method. </p>
*
* <p> Unless overridden, this method synchronizes on the result of
* {@link #getClassLoadingLock <tt>getClassLoadingLock</tt>} method
* during the entire class loading process.
*
* @param name
* The <a href="#name">binary name</a> of the class
*
* @param resolve
* If <tt>true</tt> then resolve the class
*
* @return The resulting <tt>Class</tt> object
*
* @throws ClassNotFoundException
* If the class could not be found
*/
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
c = findClass(name);
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
加載使用指定二進(jìn)制名字的類。這個(gè)方法默認(rèn)的實(shí)現(xiàn)拾因,會(huì)按照如下的順序來(lái)查找這個(gè)類:
① 調(diào)用『findLoadedClass(String)』方法來(lái)檢查這個(gè)類是否已經(jīng)被加載了旺罢。
② 調(diào)用父類加載器的『loadClass』方法旷余。如果父類加載器是null,那么虛擬機(jī)內(nèi)建的類加載器(bootstrap class loader)會(huì)被使用主经。
③ 調(diào)用『findClass(String)』方法來(lái)尋找類荣暮。
如果類在上述步驟中被找到了,并且“解析”標(biāo)志位true罩驻,那么這個(gè)方法接下來(lái)會(huì)在結(jié)果類對(duì)象上調(diào)用『resolveClass(Class)』穗酥。ClassLoader類的子類被鼓勵(lì)去重寫(xiě)『findClass(String)』,而非當(dāng)前方法惠遏。
除非被重寫(xiě)砾跃,否則這個(gè)方法會(huì)同步『getClassLoadingLock』方法的結(jié)果在整個(gè)類加載的過(guò)程期間(以確保每個(gè)類只會(huì)被加載一次)。
相關(guān)文章
深入淺出“類加載器”
深入探索“線程上下文類加載器”
從 sun.misc.Launcher 類源碼深入探索 ClassLoader