关于java中文件路径

1、Class.getResourceAsStream 和 ClassLoader.getResourceAsStream的区别

(1)Class.getResourceAsStream:

​ path 不以’/'开头时默认是从此类所在的包下取资源,以’/'开头则是从classpath下获取。其只是通过path构造一个绝对路径,最终还是由ClassLoader获取资源。


public InputStream getResourceAsStream(String name) {
    //解析name的路径,若不以‘/’开头,则拼接上该类所在的包路径
    //如: com.abc.Test.class ,则会拼接为 com/abc/name
    name = resolveName(name);
    ClassLoader cl = getClassLoader0();
    if (cl==null) {
        // A system class.
        return ClassLoader.getSystemResourceAsStream(name);
    }
    return cl.getResourceAsStream(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;
}
(2)ClassLoader.getResourceAsStream:

默认则是从ClassPath根下获取,path不能以’/'开头,最终是由ClassLoader获取资源。

public class TestC {
    @Test
    public void test1(){
        InputStream resourceAsStream = TestC.class.getResourceAsStream("123.properties");
        InputStream resourceAsStream1 = TestC.class.getClassLoader().getResourceAsStream("testresource/a/123.properties");
        System.out.println(resourceAsStream);
        System.out.println(resourceAsStream1);
    }
}
运行结果:
java.io.BufferedInputStream@2d6a9952
java.io.BufferedInputStream@22a71081
关于java中文件路径_第1张图片
微信图片_20201219165328.png

2、Class.class.getResource 和 ClassLoader.getResource:

​ (1)Class.class.getResource: path 不以’/'开头时默认是从此类所在的包下取资源,以’/'开头则是从classpath下获取。其只是通过path构造一个绝对路径,最终还是由ClassLoader获取资源。

@Test
public void test() {
    URL resource = TestC.class.getResource("");
    System.out.println(resource);
    URL resource1 = TestC.class.getClassLoader().getResource("");
    System.out.println(resource1);
}

运行结果:
file:/E:/code/test2/target/classes/testresource/a/
file:/E:/code/test2/target/classes/
3、关于Class.class.getResource的详解

​ 先贴源码

//父加载器
private final ClassLoader parent;

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;
}

​ 试验以上结论:

​ 首先,创建了一个项目,里面仅包含两个文件,并将其打成jar包,放入扩展类加载器的目标目录中


关于java中文件路径_第2张图片
image-20201217173302812.png
关于java中文件路径_第3张图片
image-20201217173400634.png

@Test
public void test() {
    URL resource = TestC.class.getResource("/test1.xml");
    System.out.println(resource);

    URL resource1 = TestC.class.getClassLoader().getResource("test1.xml");
    System.out.println(resource1);
}

运行结果:
jar:file:/D:/worksoft/java/jre/lib/ext/test3-1.0-SNAPSHOT.jar!/test1.xml
jar:file:/D:/worksoft/java/jre/lib/ext/test3-1.0-SNAPSHOT.jar!/test1.xml
补充一下java类加载器相关知识:
  1. 启动类加载器(Bootstrap/Primordial/NULL ClassLoader):顶层的类加载器,没有父类加载器。负责加载 /lib 目录下的,或则被 -Xbootclasspath 参数所指定路径中的,并被 JVM 识别的(仅按文件名识别,如 rt.jar,名字不符合的类库即使放在 lib 目录也不会被加载)类库加载到虚拟机内存中。所有被 Bootstrap classloader 加载的类,它的 Class.getClassLoader 方法返回的都是 null,所以也称作 NULL ClassLoader。

  2. 扩展类加载器(Extension CLassLoader):由 sun.misc.Launcher$ExtClassLoader 实现,负责加载 /lib/ext 目录下,或被 java.ext.dirs 系统变量所指定的目录下的所有类库;

  3. 应用程序类加载器(Application/System ClassLoader):由 sun.misc.Launcher$AppClassLoader 实现。它是 ClassLoader.getSystemClassLoader() 方法的默认返回值,所以也称为系统类加载器(System ClassLoader)。它负责加载 classpath 下所指定的类库,如果应用程序没有自定义过自己的类加载器,一般情况下这个就是程序中默认的类加载器。

关于java中文件路径_第4张图片
双亲委派模式.png
关于java中文件路径_第5张图片
image-20201217173207489.png

你可能感兴趣的:(关于java中文件路径)