本帖最后由 张11。。。 于 2019-9-9 11:22 编辑
Java基础之类加载器 概述
类加载器: 负责将.class文件加载到内存中,并为之生成对应的Class对象,也就是字节码文件对象。 问题:我们平时书写在eclipse中的Java程序是如何运行的呢? 1)首先将 .java 源文件编译为class类文件; 2)编译后的类文件是存在硬盘中的,那么我们运行需要在内存中看到效果,那么类文件是如何被加载到内存中的呢,就是jvm通过类加载器ClassLoader把硬盘中的class文件加载到内存中,这样就可以使用这个类中的成员变量和方法了。而被加载到内存中这个class文件就会变成一个Class类的对象。 常见的类加载器有三种,每个类加载器负责加载不同位置的类: 1)Bootstrap 根类加载器; 2)ExtClassLoader 扩展类加载器; 3)AppClassLoader 系统/应用类加载器; 那么这三种类加载器各有什么作用或者有什么区别呢? 他们三个加载的范围是不一样的。如下图所示: 说明: 1)Bootstrap是最顶级的类加载器。它加载类文件不是我们自己书写的,负责Java核心类的,比如System,String等。只有所有类加载到内存中,我们才可以使用。 2)ExtClassLoader 扩展类加载器,加载的是扩展类的,我们是用不到的,都是jdk内部自己使用的。 3)AppClassLoader 系统/应用类加载器,是用来加载ClassPath 指定的所有jar或目录,ClassPath表示存放类路径的,我们如果不配置ClassPath,那么就表示当前文件夹,在idea环境下的ClassPath是out目录。在out目录存放的都是我们书写好的class文件,也就是说 AppClassLoader 类加载器是用来加载我们书写的out目录下的class文件。 需求:演示类加载器的父子关系。 代码演示如下所示: 分析:如何获取一个类的类加载器呢? 如果想获得当前类的加载器,那么首先必须获得当前类的字节码文件对象,而这个字节码文件对象属于Class类型,我们可以使用 Class类中的getClassLoader()函数来获得类加载器: ClassLoadergetClassLoader() 返回该类的类加载器 AppClassLoader:加载classPath中的所有的类,也就是我们自己写的那些类! 注意:类加载器,也是一个类,也需要被加载。一般类加载器都是被父类加载器加载的! 获取父类加载器的方法:使用ClassLoader 类中的getParent()返回委托的父类加载器 。 说明:AppClassLoader是被ExtClassLoader加载的! ExtClassLoader肯定也是一个类,需要被父加载,它的父亲是BootStrap。 那么问题来了:如果这个类加载器也需要被人加载,那么就没有尽头了!因此,BootStrap是不需要被加载的。 因为它不是一个Java类。它是用C++实现的一段代码。 也就是说,jvm虚拟机一启动就会运行C++实现的这段代码,那么BootStrap类一旦被启动就会开始加载他下面的子类了。 注意:最顶级的类加载器不是Java类,而是C++实现的代码。
/*
* 演示类加载器的父子关系:
* 获取一个类加载器:使用Class类中的函数:ClassLoadergetClassLoader() 返回该类的类加载器
* 获取Class类的对象 :类名.class
* AppClassLoader:加载classPath中的所有的类,也就是我们自己写的那些类!
* 类加载器,也是一个类,也需要被加载。一般类加载器都是被父类加载器加载的!
* 获取父类加载器的方法:使用ClassLoader类中的函数:
* ClassLoadergetParent()返回委托的父类加载器
*
* AppClassLoader类加载器是被ExtClassLoader类加载器加载的!
*
* ExtClassLoader肯定也是一个类,需要被父类加载器加载,它的父类是BootStrap类加载器。
* 而ExtClassLoader确实被他的父类BootStrap类加载器加载的,
* 那么问题来了:如果BootStrap类加载器也需要被人加载,那么就没有尽头了!因此,BootStrap类加载器是不需要被加载的。
* 因为它不是一个Java类。它是用C++语言实现的一段代码。
* 所以这里获取不到BootStrap类加载器,就是因为他是一段C++代码实现的。
*/
public class ClassLoaderDemo1 {
public static void main(String[] args) {
// 获取当前类的加载器
ClassLoader loader = ClassLoaderDemo1.class.getClassLoader();
//输出当前类的类加载器
System.out.println(loader);//sun.misc.Launcher$AppClassLoader@b0014f0
//获取AppClassLoader类加载器的父类
ClassLoader parent = loader.getParent();
//输出AppClassLoader类加载器的父类加载器
System.out.println(parent);//sun.misc.Launcher$ExtClassLoader@325e9e34
//获取ExtClassLoader类加载器的父类
ClassLoader grandpa = parent.getParent();
//输出ExtClassLoader类加载器的父类加载器
System.out.println(grandpa);//null
}
}
注意: 通过上述学习我们发现三种类加载器都有自己要加载的类文件,各司其职,不能乱加载,比如Bootstrap类加载器只能加载sun公司定义好的类,他就不能加载自定义的类文件。所有的自定义类文件都是由AppClassLoader类加载器加载。 使用类加载器加载配置文件的方式
需求:用类加载器加载配置文件。 代码步骤: 1)新建一个类ClassLoaderDemo2 ,并书写main函数; 2)在当前项目下新建一个stu.ini文件,并在其中输入: name=zhangsan age=19 3)创建Properties 类的集合对象p; 4)创建字节输入流FileInputStream对象关联项目根目录文件stu.ini; 5)使用集合对象p调用load函数加载配置文件中的内容,并使用输出语句输出内容即可; 使用之前的FileInputStream方式加载配置文件方式加载文件内容:
//使用之前的加载配置文件方式加载文件内容
public void method_1() throws Exception{
// 创建Properties类的对象
Properties p = new Properties();
//调用函数加载配置文件中内容
p.load(new FileInputStream("stu.ini"));
//输出内容
System.out.println(p);
}
说明:直接使用FileInputStream的相对路径,是相对于项目。 注意:我们在开发中配置文件stu.ini不仅可以存放到项目的根目录,有时我们还会存放到src下面: 这样我们使用new FileInputStream("stu.ini")在读取就会出现如下问题: 错误原因:new FileInputStream("stu.ini")是去项目的根目录去查找stu.ini文件,而由于我们已经将该文件移动到src下面,所以会报找不到指定文件的异常。 既然使用之前的加载方式加载src下面的配置文件有问题,那么我们可以使用新的加载方式,就是用类加载器加载。 分析步骤: 1)使用当前类ClassLoaderDemo2获得Class对象并调用Class类中的getClassLoader()函数: ClassLoaderloader = ClassLoaderDemo2.class.getClassLoader(); 2)使用类加载器对象loader 调用ClassLoader 类中的InputStream getResourceAsStream(String name)返回读取指定资源的输入流 InputStream in =loader.getResourceAsStream("stu.ini"); 说明:这里的name是文件的路径:这个路径如果使用相对路径,相对的是src目录。 代码演示如下所示:
//使用之前的加载配置文件方式加载文件内容
public void method_1() throws Exception{
// 创建Properties类的对象
Properties p = new Properties();
//获取当前类的加载器
ClassLoader loader = ClassLoaderDemo2.class.getClassLoader();
//使用类加载器对象调用函数获取加载配置文件的字节输入流
InputStream in = loader.getResourceAsStream("stu.ini");
//调用函数加载配置文件中内容
// p.load(new FileInputStream("stu.ini"));
p.load(in);
//输出内容
System.out.println(p);
}
总结:这两种加载文件的区别在于加载的相对位置不一样,第一种方式相对的是当前项目,而第二种方式相对的是src。
|