本文主要是研究下面集中方法到底谁才能真正的load到文件,你能一眼看出来吗?
GetResourcesSample.class.getClassLoader.getResourceAsStream("main-resources-file.txt")
GetResourcesSample.class.getClass().getResourceAsStream("main-resources-file.txt")
GetResourcesSample.class.getResourceAsStream("main-resources-file.txt")
GetResourcesSample.class.getClassLoader.getResourceAsStream("/main-resources-file.txt")
GetResourcesSample.class.getClass().getResourceAsStream("/main-resources-file.txt")
GetResourcesSample.class.getResourceAsStream("/main-resources-file.txt")
很晕吧,反正我是挺晕的。
目录结构:
代码:
public class GetResourcesSample { private static final String MAIN_FILE = "main-resources-file.txt"; private static final String MAIN_FILE_WITH_SLASH = "/main-resources-file.txt"; private static final String TEST_FILE = "test-resources-file.txt"; private static final String TEST_FILE_WITH_SLASH = "/test-resources-file.txt"; private static final String ROOT_FILE = "project-root-file.txt"; private static final String ROOT_FILE_WITH_SLASH = "./project-root-file.txt"; public static void main(String[] args) { validateResult(MAIN_FILE); validateResult(MAIN_FILE_WITH_SLASH); validateResult(TEST_FILE); validateResult(TEST_FILE_WITH_SLASH); validateResult(ROOT_FILE); validateResult(ROOT_FILE_WITH_SLASH); } private static void validateResult(String file) { InputStream inputStream1 = GetResourcesSample.class.getClass().getResourceAsStream(file); if (inputStream1 != null) { System.out.println(MessageFormat .format("GetResourcesSample.class.getClass().getResourceAsStream(\"{0}\") is not null!", file)); } InputStream inputStream2 = GetResourcesSample.class.getResourceAsStream(file); if (inputStream2 != null) { System.out.println( MessageFormat.format("GetResourcesSample.class.getResourceAsStream(\"{0}\") is not null!", file)); } InputStream inputStream3 = GetResourcesSample.class.getClassLoader().getResourceAsStream(file); if (inputStream3 != null) { System.out.println( MessageFormat.format("GetResourcesSample.class.getClassLoader().getResourceAsStream(\"{0}\") is not null!", file)); } } }
结果:
GetResourcesSample.class.getClassLoader().getResourceAsStream("main-resources-file.txt") is not null!
GetResourcesSample.class.getClass().getResourceAsStream("/main-resources-file.txt") is not null!
GetResourcesSample.class.getResourceAsStream("/main-resources-file.txt") is not null!
结论:
- Class.getResourceAsStream 最终调用的是此Class的Class Loader的getResourceAsStream来进行读文件(有些绕,尽量理解)
- GetResourcesSample.class.getClass() 得到的是Class这个类的实例,它的ClassLoader是JVM的bootstrap Class Loader
- GetResourcesSample.class.getResourceAsStream 由于去resolve了一下name,虽然是当前class的ClassLoader,它也读不到这个文件;除非你的文件名以“/”开头。详见源代码:
/** * Add a package name prefix if the name is not absolute Remove leading "/" * if name is absolute */ 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; }
- project-root-file.txt这种最后最终不被打在Jar包里的文件,是没有机会被读取的,除非hard code一个文件所在的绝对路径
- 把相同代码放到UT里面去跑,会发现UT能同时load到main和test下的文件。因为JUnit有它自己的ClassLoader,它能同时读到main和test下的文件。