class.getResourceAsStream与class.getClassLoader().getResourceAsStream区别

1、基本使用:

创建一个配置文件classloaderResource.properties用于数据读取,以及一个测试类GetResourceTest
在这里插入图片描述

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

public class GetResourceTest {
    
    
    public static void main(String[] args) throws IOException {
    
    
        InputStream inputStream = GetResourceTest.class
                .getResourceAsStream("classloaderResource.properties");
        Properties properties = new Properties();
        properties.load(inputStream);
        properties.list(System.out); //遍历输出
    }
}

在这里插入图片描述

两种用法:
1:类名.class.getClassLoader().getResourceAsStream(“文件名”) | 一般为key-value形式的文件,如.properties
2:类名.class.getResourceAsStream(“文件名”)

2、两种方法区别

1:类名.class.getClassLoader()相当于从classpath下开始读取;
2:类名.class.getResourceAsStream(“文件名”)从当前类所在路径下读取。

Scene1: classloaderResource.properties文件放在根目录下:
在这里插入图片描述

类名.class.getClassLoader() 需要使用以下代码读取

InputStream inputStream = GetResourceTest.class.getClassLoader()
        .getResourceAsStream("classloaderResource.properties");

而使用 类名.class.getResourceAsStream(“文件名”)则需要

InputStream inputStream = GetResourceTest.class.getClassLoader()
        .getResourceAsStream("/classloaderResource.properties");

Scene2: classloaderResource.properties文件放在包中时:
在这里插入图片描述
类名.class.getClassLoader() 需要使用以下代码读取(src下第一层包名开始)

InputStream inputStream = GetResourceTest.class.getClassLoader()
    .getResourceAsStream("JavaTest/classloader/classloaderResource.properties");     

而使用 类名.class.getResourceAsStream(“文件名”)则需要

InputStream inputStream = GetResourceTest.class
        .getResourceAsStream("classloaderResource.properties");

踩坑

今天在该项目下新建了一个Module,然后在该Module的gson包下新建了一个json文件,使用上述方式死活读不到,NullPointerException异常!json文件移到resources文件夹中可以读取,啊,这,莫非,上述这种模式只能在该项目下(非Module)才能正常?所以非java文件统一规范放到resources目录下(子文件夹也不会报错),以减少不必要的错误。
在这里插入图片描述

基础理解

都是实现获取在classpath路径下的资源文件的输入流。

为什么是classpath而不是src,因为当web项目运行时,IDE编译器会把src下的一些资源文件移至WEB-INF/classes,classPath目录其实就是这个classes目录。这个目录下放的一般是web项目运行时的class文件、资源文件(xml,properties…);

另外,在使用springboot进行开发时,其目录默认不是WEB-INF而是BOOT-INF,但是其含义是一样的。具体如下图所示:

img

上图,蓝框中即为classpath中的内容,也就是自己实际编写的代码,另外依赖的代码主要在lib目录下。

再从另外一个视角对比下,编译前后文件所在目录的变化

编译前:

img

编译后:

img

class是指当前类的class对象,getClassLoader()是获取当前的类加载器,什么是类加载器?简单点说,就是用来加载java类的,类加载器负责把class文件加载进内存中,并创建一个java.lang.Class类的一个实例,也就是class对象,并且每个类的类加载器都不相同。getResourceAsStream(path)是用来获取资源的,而类加载器默认是从classPath下获取资源的,因为这下面有class文件吗,所以这段代码总的意思是通过类加载器在classPath目录下获取资源.并且是以流的形式。

我们知道在Java中所有的类都是通过加载器加载到虚拟机中的,而且类加载器之间存在父子关系,就是子知道父,父不知道子,这样不同的子加载的类型之间是无法访问的(虽然它们都被放在方法区中),所以在这里通过当前类的加载器来加载资源也就是保证是和类类型同一个加载器加载的。

不同点

1. class.getClassLoader().getResourceAsStream(String name)

默认从classpath中找文件(文件放在resources目录下),name不能带“/”,否则会抛空指针

eg:

InputStream stream = Thread.currentThread().getContextClassLoader().getResourceAsStream("gamvanclub.cfg.xml");

2. class.getResourceAsStream(String name)

通过给定名称查找资源,查询资源的规则由给定的类的class load来实现,这个方法由类的loader来执行;如果这个类由bootstrap加载,那么方法由ClassLoader.getSystemResourceAsStream代理执行。

代理之前,绝对的资源名称通过传入的name参数以下算法进行构造:

如果name以"/"开头,那么绝对路径是/后边跟的名字

eg:

//从classpath下的config相对路径中读取config.ini"
mypackage.Hello.class.getResourceAsStream("/config/config.ini");

如果name不是以"/“开头,那么绝对路径是package名”."换成“/”以后再加name。

eg:

//com.abc.App就是/com/abc/App/name 或者写作 : ../../name(以class所在路径为基准,文件相对于该类的路径)

Java类加载过程

3个步骤:

1.加载,加载类的二进制文件。

2.链接:

(1)验证,验证字节码的结构是否正确

(2)准备,给静态成员分配空间并赋予默认值(注意这里:静态变量的第一次赋值是在类加载的时候就进行了,与后面初始化的时候的自定义赋值不是同一过程,也就是静态成员在初始化的时候可能已被赋值二次了)

(3)解析,将符号引用变为直接引用

3初始化,为静态成员赋予自己给定的初值

类的实例化的顺序:

(1)静态成员、方法与静态代码块的初始化与执行

(2)普通成员、方法与普通代码块的初始化与执行

(3)构造函数的执行(父类的构造函数先执行)

猜你喜欢

转载自blog.csdn.net/qq_43842093/article/details/130663768
今日推荐