这两个方法,接收一个资源的路径参数name,返回一个代表资源的url或输入流。与linux中的文件定位类似,若name以“/”开头,此时将name视为绝对路径,后续classLoader会尝试以每一个classpath为根,以name为后续路径去寻找资源;若name不以“/”开头,则name为相对路径,相对于当前class对象对应类所在的包,在这个包路径的基础上以name为后续路径寻找资源。
1.getResource方法:
public java.net.URL getResource(String name) {
//转换name为绝对路径
name = resolveName(name);
ClassLoader cl = getClassLoader0();
if (cl==null) {
// A system class.
return ClassLoader.getSystemResource(name);
}
//实际上委托给classLoader
return cl.getResource(name);
}
resolveName方法:
这个方法对name参数的格式进行转换,假如当前class对象所在包为com.test,则对于相对路径“a/b/c”,返回“com/test/a/b/c”;对于绝对路径"/a/b/c",返回"a/b/c"。
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;
}
name被转换后传给ClassLoader类的getResource方法:
类似于双亲委派机制,每个classLoader首先委派给父类classLoader去定位name对应的资源,父类classLoader定位不到时,则自己去定位,最终相当于在每一个的classpath中尝试以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;
}
2.getResourceAsStream方法:
类似于getResource,转换name后委托给classLoader的getResourceAsStream方法
public InputStream getResourceAsStream(String name) {
name = resolveName(name);
ClassLoader cl = getClassLoader0();
if (cl==null) {
// A system class.
return ClassLoader.getSystemResourceAsStream(name);
}
return cl.getResourceAsStream(name);
}
ClassLoader类的getResourceAsStream方法:
public InputStream getResourceAsStream(String name) {
//简单的调用该类的getResource方法,上文已经提到过
URL url = getResource(name);
try {
return url != null ? url.openStream() : null;
} catch (IOException e) {
return null;
}
}