测试代码及输出结果
目录结构
├── src
│ ├── main
│ ├── java
│ │ └── com
│ │ └── example
│ │ └── coco
│ │ ├── Main.java
│ └── resources
│ └── definition.properties
│ └── test
└── target
└── classes
├── com
└── definition.properties
Main.java
public class Main {
public static void main(String[] args) {
// 组1
System.out.println(Main.class.getResource("definition.properties"));
System.out.println(Main.class.getResource("/definition.properties"));
// 组2
System.out.println(Main.class.getClass().getResource("definition.properties"));
System.out.println(Main.class.getClass().getResource("/definition.properties"));
// 组3
System.out.println(Main.class.getClassLoader().getResource("definition.properties"));
System.out.println(Main.class.getClassLoader().getResource("/definition.properties"));
// AppClassLoader
System.out.println(Main.class.getClassLoader());
// ExtClassLoader
System.out.println(Main.class.getClassLoader().getParent());
// BootstrapClassLoader(Java中用null表示)
System.out.println(Main.class.getClassLoader().getParent().getParent());
System.out.println(Main.class.getClass().getClassLoader());
}
输出
null
file:/D:/learning/demo/target/classes/definition.properties
null
file:/D:/learning/demo/target/classes/definition.properties
file:/D:/learning/demo/target/classes/definition.properties
null
sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$ExtClassLoader@4f023edb
null
null
组1 class.getResource 分析
Class.getResource源码
public java.net.URL getResource(String name) {
name = resolveName(name);
ClassLoader cl = getClassLoader0();
if (cl==null) {
// A system class.
return ClassLoader.getSystemResource(name);
}
return cl.getResource(name);
}
Class.resolveName源码
可以看到
resolveName 方法会去判断 传入的参数name是否以 /开头,如果不是/开头,则会使用当前方法的调用类com.example.coco.Main所在包作为前缀(com/example/coco/),然后拼接参数name(definition.properties),最终返回 com/example/coco/definition.properties,但是显然这个路径是不存在的,所以
Main.class.getResource("definition.properties") 返回 null
而如果是/开头,resolveName返回definition.properties,继续调用ClassLoader.getResource方法
可以看出定位到了正确的目录
/D:/learning/demo/target/classes/definition.properties
那是如何定位的呢?
Main.java的ClassLoader是 AppClassLoader, 它会从classpath中去查找definition.properties是否存在
classpath是什么?
当你使用Idea点运行Main.java的时候,其实是在拼一串命令行,类似 java Main,只不过Idea拼接了很多参数,如下图:
拷贝出来如下:
"C:\Program Files\Java\jdk1.8.0_181\bin\java.exe"
"-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3\lib\idea_rt.jar=54345:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3\bin"
-Dfile.encoding=UTF-8
-classpath
"C:\Program Files\Java\jdk1.8.0_181\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\deploy.jar;
C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\access-bridge-64.jar;
C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\cldrdata.jar;
C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\dnsns.jar;
C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\jaccess.jar;
C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\jfxrt.jar;
C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\localedata.jar;
C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\nashorn.jar;
C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunec.jar;
C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunjce_provider.jar;
C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunmscapi.jar;
C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunpkcs11.jar;
C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\zipfs.jar;
C:\Program Files\Java\jdk1.8.0_181\jre\lib\javaws.jar;
C:\Program Files\Java\jdk1.8.0_181\jre\lib\jce.jar;
C:\Program Files\Java\jdk1.8.0_181\jre\lib\jfr.jar;
C:\Program Files\Java\jdk1.8.0_181\jre\lib\jfxswt.jar;
C:\Program Files\Java\jdk1.8.0_181\jre\lib\jsse.jar;
C:\Program Files\Java\jdk1.8.0_181\jre\lib\management-agent.jar;
C:\Program Files\Java\jdk1.8.0_181\jre\lib\plugin.jar;
C:\Program Files\Java\jdk1.8.0_181\jre\lib\resources.jar;
C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar;
D:\learning\demo\target\classes"
com.example.coco.Main
其中classpath这个参数的最后一行为D:\learning\demo\target\classes, 其实这就是我们项目的编译后的输出目录:
组2 class.getClass().getResource分析
Main.class.getClass().getResource("definition.properties")
可以看到getResource方法的实际调用者为
java.lang.Class,而且传入进来的name未以/开头,所以最终name为java/lang/definition.properties, 而这个路径是不存在的,所以
Main.class.getClass().getResource("definition.properties") 返回null
Main.class.getClass().getResource("/definition.properties")
Main.class.getClass 为 java.lang.Class, 该类的类加载器为为null,即ClassLoader为BootstrapClassLoader
当为
null时最终会调用AppClassLoader.getResource方法
ClassLoader
关于ClassLoader类加载机制,可以参考我的另一篇博客类加载机制