转载自: http://swiftlet.net/archives/868
在Java中获取资源的时候,经常用到Class.getResource和ClassLoader.getResource,本文给大家说一下这两者方法在获取资源文件的路径差异。
Class.getResource(String path)
path不以’/’开头时,默认是从此类所在的包下取资源;path以’/’开头时,则是从项目的ClassPath根下获取资源。在这里’/’表示ClassPath
JDK设置这样的规则,是很好理解的,path不以’/’开头时,我们就能获取与当前类所在的路径相同的资源文件,而以’/’开头时可以获取ClassPath根下任意路径的资源。
如下所示的例子:
publicclassTest
{
publicstaticvoidmain(String[]args)
{
System.out.println(Test.class.getResource(""));
System.out.println(Test.class.getResource("/"));
}
}
运行结果为:
file:/D:/work_space/java/bin/net/swiftlet/
file:/D:/work_space/java/bin/
Class.getClassLoader().getResource(String path)
path不能以’/’开头时,path是指类加载器的加载范围,在资源加载的过程中,使用的逐级向上委托的形式加载的,’/’表示Boot ClassLoader中的加载范围,因为这个类加载器是C++实现的,所以加载范围为null。如下所示:
publicclassTest
{
publicstaticvoidmain(String[]args)
{
System.out.println(Test.class.getClassLoader().getResource(""));
System.out.println(Test.class.getClassLoader().getResource("/"));
}
}
运行结果为:
file:/D:/work_space/java/bin/
null
从上面可以看出:
class.getResource(“/”) == class.getClassLoader().getResource(“”)
其实,Class.getResource和ClassLoader.getResource本质上是一样的,都是使用ClassLoader.getResource加载资源的。下面请看一下jdk的Class源码:
public java.net.URLgetResource(Stringname)
{
name=resolveName(name);
ClassLoadercl=getClassLoader0();
if(cl==null)
{
// A system class.
returnClassLoader.getSystemResource(name);
}
returncl.getResource(name);
}
从上面就可以看才出来:Class.getResource和ClassLoader.getResource本质上是一样的。至于为什么Class.getResource(String path)中path可以’/’开头,是因为在name = resolveName(name);进行了处理:
privateStringresolveName(Stringname)
{
if(name==null)
{
returnname;
}
if(!name.startsWith("/"))
{
Classc=this;
while(c.isArray()){
c=c.getComponentType();
}
StringbaseName=c.getName();
intindex=baseName.lastIndexOf('.');
if(index!=-1)
{
name=baseName.substring(0,index).replace('.','/')
+"/"+name;
}
}else
{//如果是以"/"开头,则去掉
name=name.substring(1);
}
returnname;
}
demo:
ClassLoaderDemo demo = new ClassLoaderDemo();
Class<? extends ClassLoaderDemo> clazz = demo.getClass();
URL clazzUrl = clazz.getResource("");
System.out.println("clazzUrl = " + clazzUrl.getPath());
URL classLoaderUrl = demo.getClass().getClassLoader().getResource("");
System.out.println("classLoaderUrl = " + classLoaderUrl.getPath());
URL systemUrl = ClassLoader.getSystemResource("");
System.out.println("systemUrl = " + systemUrl.getPath());
输出:
clazzUrl = /F:/source/spring/myspring/myspring/target/test-classes/myspring/
classLoaderUrl = /F:/source/spring/myspring/myspring/target/test-classes/
systemUrl = /F:/source/spring/myspring/myspring/target/test-classes/
另:
className.class.getResourceAsStream()与ClassLoader.getSystemResourceAsStream() 的区别
className.class.getResourceAsStream :
一: 要加载的文件和.class文件在同一目录下,例如:com.x.y 下有类Test.class ,同时有资源文件config.properties
那么,应该有如下代码:
//前面没有“/”代表当前类的目录
InputStream is1 = Test.class.getResourceAsStream("config.properties");
System.out.println(is1);// 不为null
第二:在Test.class目录的子目录下,例如:com.x.y 下有类Test.class ,同时在 com.x.y.prop目录下有资源文件config.properties
那么,应该有如下代码:
//前面没有“/”代表当前类的目录
InputStream is2 = Test.class.getResourceAsStream("prop/config.properties");
System.out.println(is2);//不为null
第三:不在同目录下,也不在子目录下,例如:com.x.y 下有类Test.class ,同时在 com.m.n 目录下有资源文件config.properties
那么,应该有如下代码:
//前面有“/”,代表了工程的根目录
InputStream is3 = Test.class.getResourceAsStream("/com/m/n/config.properties");
System.out.println(is3);//不为null
ClassLoader.getSystemResourceAsStream :
和className.class.getResourceAsStream 的第三种取得的路径一样,但少了“/”
InputStream is4 = ClassLoader.getSystemResourceAsStream("properties/PayManagment_Config.properties");
System.out.println(is4);//不为null
声明: 本文由金丝燕网原创编译,转载请保留链接: Class.getResource和ClassLoader.getResource的区别分析