1妒蛇、Class.getResourceAsStream 和 ClassLoader.getResourceAsStream的區(qū)別
(1)Class.getResourceAsStream:
? path 不以’/'開頭時(shí)默認(rèn)是從此類所在的包下取資源蕉朵,以’/'開頭則是從classpath下獲取佛吓。其只是通過path構(gòu)造一個(gè)絕對路徑,最終還是由ClassLoader獲取資源威根。
public InputStream getResourceAsStream(String name) {
//解析name的路徑艘蹋,若不以‘/’開頭内边,則拼接上該類所在的包路徑
//如: com.abc.Test.class ,則會拼接為 com/abc/name
name = resolveName(name);
ClassLoader cl = getClassLoader0();
if (cl==null) {
// A system class.
return ClassLoader.getSystemResourceAsStream(name);
}
return cl.getResourceAsStream(name);
}
/**
* 解析路徑
*/
private String resolveName(String name) {
if (name == null) {
return name;
}
if (!name.startsWith("/")) {
Class<?> c = this;
while (c.isArray()) {
c = c.getComponentType();
}
//獲取類的全限定名
String baseName = c.getName();
int index = baseName.lastIndexOf('.');
if (index != -1) {
name = baseName.substring(0, index).replace('.', '/')
+"/"+name;
}
} else {
name = name.substring(1);
}
return name;
}
(2)ClassLoader.getResourceAsStream:
默認(rèn)則是從ClassPath根下獲取,path不能以’/'開頭索绪,最終是由ClassLoader獲取資源湖员。
public class TestC {
@Test
public void test1(){
InputStream resourceAsStream = TestC.class.getResourceAsStream("123.properties");
InputStream resourceAsStream1 = TestC.class.getClassLoader().getResourceAsStream("testresource/a/123.properties");
System.out.println(resourceAsStream);
System.out.println(resourceAsStream1);
}
}
運(yùn)行結(jié)果:
java.io.BufferedInputStream@2d6a9952
java.io.BufferedInputStream@22a71081
2、Class.class.getResource 和 ClassLoader.getResource:
? (1)Class.class.getResource: path 不以’/'開頭時(shí)默認(rèn)是從此類所在的包下取資源瑞驱,以’/'開頭則是從classpath下獲取娘摔。其只是通過path構(gòu)造一個(gè)絕對路徑,最終還是由ClassLoader獲取資源唤反。
@Test
public void test() {
URL resource = TestC.class.getResource("");
System.out.println(resource);
URL resource1 = TestC.class.getClassLoader().getResource("");
System.out.println(resource1);
}
運(yùn)行結(jié)果:
file:/E:/code/test2/target/classes/testresource/a/
file:/E:/code/test2/target/classes/
3凳寺、關(guān)于Class.class.getResource的詳解
? 先貼源碼
//父加載器
private final ClassLoader parent;
public URL getResource(String name) {
URL url;
if (parent != null) {
//雙親委派模式,先讓父加載器去加載
url = parent.getResource(name);
} else {
//到達(dá)系統(tǒng)啟動(dòng)類加載器
url = getBootstrapResource(name);
}
if (url == null) {
//若父加載器找不到,則由當(dāng)前類加載器嘗試加載
url = findResource(name);
}
return url;
}
? 試驗(yàn)以上結(jié)論:
? 首先,創(chuàng)建了一個(gè)項(xiàng)目,里面僅包含兩個(gè)文件,并將其打成jar包,放入擴(kuò)展類加載器的目標(biāo)目錄中
?
@Test
public void test() {
URL resource = TestC.class.getResource("/test1.xml");
System.out.println(resource);
URL resource1 = TestC.class.getClassLoader().getResource("test1.xml");
System.out.println(resource1);
}
運(yùn)行結(jié)果:
jar:file:/D:/worksoft/java/jre/lib/ext/test3-1.0-SNAPSHOT.jar!/test1.xml
jar:file:/D:/worksoft/java/jre/lib/ext/test3-1.0-SNAPSHOT.jar!/test1.xml
補(bǔ)充一下java類加載器相關(guān)知識:
啟動(dòng)類加載器(Bootstrap/Primordial/NULL ClassLoader):頂層的類加載器,沒有父類加載器彤侍。負(fù)責(zé)加載 /lib 目錄下的肠缨,或則被 -Xbootclasspath 參數(shù)所指定路徑中的,并被 JVM 識別的(僅按文件名識別盏阶,如 rt.jar晒奕,名字不符合的類庫即使放在 lib 目錄也不會被加載)類庫加載到虛擬機(jī)內(nèi)存中。所有被 Bootstrap classloader 加載的類名斟,它的
Class.getClassLoader
方法返回的都是null
脑慧,所以也稱作 NULL ClassLoader。擴(kuò)展類加載器(Extension CLassLoader):由
sun.misc.Launcher$ExtClassLoader
實(shí)現(xiàn)砰盐,負(fù)責(zé)加載<JAVA_HOME>/lib/ext
目錄下闷袒,或被java.ext.dirs
系統(tǒng)變量所指定的目錄下的所有類庫;應(yīng)用程序類加載器(Application/System ClassLoader):由
sun.misc.Launcher$AppClassLoader
實(shí)現(xiàn)楞卡。它是ClassLoader.getSystemClassLoader()
方法的默認(rèn)返回值霜运,所以也稱為系統(tǒng)類加載器(System ClassLoader)脾歇。它負(fù)責(zé)加載 classpath 下所指定的類庫,如果應(yīng)用程序沒有自定義過自己的類加載器淘捡,一般情況下這個(gè)就是程序中默認(rèn)的類加載器藕各。