Class.getResourceAsStream和ClassLoader.getResourceAsStream的区别

ClassLoader.getResourceAsStream

根据指定的资源名称读取该资源的输入流InputStream

public InputStream getResourceAsStream(String name) {
        URL url = getResource(name);
        try {
            return url != null ? url.openStream() : null;
        } catch (IOException e) {
            return null;
        }
    }

可见,真正的加载逻辑在java.lang.ClassLoader#getResource(String name) 方法内,其加载过程也和双亲委派模型保持一致。
BootStrap ClassLoader:/JAVA_HOME/jre/classes目录下
Extension ClassLoader:/JAVA_HOME/jre/lib/ext目录下,并且只能以jar包的形式保存
App ClassLoader:一般当前目录即为加载路径,当然也可以通过java -classpath 或者 java -Djava.class.path 指定

以上自上向下进行查找。

一般我们配合java -cp 指定的路径来实现加载资源的操作。
但是资源也可以放在 jre\classes 目录下:由 BootStrap ClassLoader 进行加载或者使用-Xbootclasspath 或者-Djava.ext.dirs 等等。

Class.getResourceAsStream

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

可以看到,cl.getResourceAsStream(name); 也就是说Class.getResourceAsStream 也是使用 ClassLoader 进行加载的。

resolveName(String name) 方法的作用:

  • 如果是绝对路径则删除前导/
  • 不是绝对路径则添加包名前缀
    事例:对于springmvc.xml(包名为cn.bjut.test),经过该方法返回cn/bjut/test/springmvc.xml

同时这也说明,我们使用ClassLoader.getResourceAsStream 加载资源是不能带有前导 / 字符的。

Class.getResourceAsStream 的恶心之处在于它有个绝对路径相对路径的问题。

测试:
构建如下的目录结构

D:\N3VERL4ND\DESKTOP\COM
└─github
    │  2.txt
    │  B.class
    │  B.java
    │
    └─demo
            1.txt
            A.class
            A.java

A.java

package com.github.demo;
public class A {
    public static void main(String[] args) {
		if (args.length != 1) {
			System.out.println("usage: java XXX args");
			return;
		}
        System.out.println(A.class.getResourceAsStream(args[0]));
    }
}

B.java

package com.github;
public class B {
    public static void main(String[] args) {
		if (args.length != 1) {
			System.out.println("usage: java XXX args");
			return;
		}
        System.out.println(B.class.getResourceAsStream(args[0]));
    }
}

这里写图片描述

对于
InputStream is = A.class.getResourceAsStream(“1.txt”);

路径不是以/开头,说明这是一个相对路径,相对的是A.class这个文件,所以,这里的“1.txt”所指的正确位置是与A.class处于同一目录下的1.txt文件。

文件"1.txt"的绝对路径名为:"/com/github/demo/1.txt" 文件"2.txt"的绝对路径名为:"/com/github/2.txt"
这里写图片描述

其实这里所谓的绝对路径其实是相对于classpath指定的类路径。(不考虑算亲委派模型的情况)
以上测试默认以D:\N3VERL4ND\DESKTOP 为根路径。等效于set classpath=.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

N3verL4nd

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值