Class 与 ClassLoader
写 java 代码时常常需要加载一些外部的资源,通常我们会使用全路径名加载一份资源,比如:C:\Users\XXX\Desktop\abc.jpg
但是,有些时候我们需要加载的是源代码路径下的资源或者配置文件等等,更习惯于使用相对路径,或者直接给一个文件名,就希望能够找到我们需要的配置文件。
如何做到?
常见的方法是使用了 class.getResource 或 classloader.getResource
并且使用绝对路径是一个很差的方式,它会导致你的程序移植性很差,尽量使用相对路径
这两个方法看起来很相似,他们直接有什么区别?
查看源代码:
Class.getResourceAsStream(String name)
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);
}
上面的代码可以看出, Class.getResourceAsStream(String name)
最终还是调用了 classloader.getResourceAsStream(String name)
。
但是两者还是有一些区别的,注意 name =resolveName(name)
这一行, Class.getResourceAsStream(String name)
在这里做了一些处理:
Class.resolveName(String 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;
}
现在看这段代码还有点云里雾绕,不妨写几行代码测试一下,看看这段代码到底在干嘛:
public class App {
public static void main(String[] args) {
System.out.println("App.class.getClassLoader().getResource(\"\") : " + App.class.getClassLoader().getResource(""));
System.out.println("App.class.getClassLoader().getResource(\"/\") : " + App.class.getClassLoader().getResource("/"));
System.out.println("App.class.getResource(\"\") : " + App.class.getResource(""));
System.out.println("App.class.getResource(\"/\") : " + App.class.getResource("/"));
}
}
输出
App.class.getClassLoader().getResource("") : file:/D:/workspace/eclipse/cluster/TestClassloader/bin/
App.class.getClassLoader().getResource("/") : null
App.class.getResource("") : file:/D:/workspace/eclipse/cluster/TestClassloader/bin/space/yukai/
App.class.getResource("/") : file:/D:/workspace/eclipse/cluster/TestClassloader/bin/
虽然上面的代码使用了 getResource,但与 getResourceAsStream 大同小异。
可以看到,
calssloder.getResource("")
方法返回了 classpath 根路径(eclipse 工程中,编译生成的类文件存放在/bin 目录下);
calssloder.getResource("/")
方法返回 null,说明 calssloder.getResource 不支持以”/“开头的参数;
class.getResource("")
方法返回了 App.class 所在的路径;
class.getResource("/")
与 calssloder.getResource("")
表现一致,返回了 classpath 的根路径
再回顾上面的代码,是否有一点明白了呢?
读取 jar 包所在的位置
有时候需要知道 jar 包所在的位置,比如我们的项目需要一个默认的日志文件输出路径,这个路径就可以是运行时 jar 包所在的目录。如何获取 jar 包所在的目录?
URL url = App.class.getProtectionDomain().getCodeSource().getLocation();
String path = url.toURL().getPath();
注意,上面的方法仅适用 jdk1.5 及以上
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于