java类的加载与加载器

java代码在计算机中经历的三个阶段:

1.Source源代码阶段(代码还是在硬盘上,并没有进入内存)   Student.java 通过javac编译 Student.class字节码文件

2.类加载器ClassLoader将字节码文件加载进入内存,成为Class类对象(成员变量Field[ ] fields、构造方法Constructor[ ] constructors、成员方法Method[ ] methods)

3.运行时阶段new Student后

Student s=new Student(); 是我们自己创建的一个类,java加载类时,用到哪个类会将该类加载。(边用边加载)

JVM如何加载Student这个类?(加载-链接-初始化)

1.JVM把Student这个类的Class对象加载进来了

第一次加载该类时,JVM先从磁盘上找到该类的字节码文件(Student.class),JVM从系统环境变量的CLASSPATH里面找字节码文件的搜索路径。

.;%JAVA_HOME%lib;%JAVA_HOME%lib ools.jar;%JAVA_HOME%libdt.jar(.代表CLASSPATH工程目录下(如要找Student类,要找对应的Module下找要加载的类),如果不是自己写的,会在后面的jdk库里面找字节码文件(如:System类.out等),将系统写好的打包放在架包里

通过类加载器,从Student.class字节码文件中,把这个类的各种信息(类名、类的属性和方法)先加载到JVM中,这些信息的集合(相当于人的户口信息)称作Class对象(大写C)

 2.链接:验证类的Class对象的合法性,开辟内存空间。

准备、验证的过程,验证当前类能够在JVM上运行(检车类的Class对象),给类的static静态成员开辟内存空间,如果当前类还有基类,继续加载其基类(执行1.2.3步)。

3.初始化

给static静态成员初始化,调用类的static静态初始化块

到此,类的加载完成了!

实例分析: 

package com.load;
/**
 * 验证类的加载
 * 任何东西.的时候,后面都会有class;
 * 2019/10/31
 */
public class ClassLoadTest {
    public static void main(String[] args) throws Exception{
        //第一种加载类的方式,只是加载类的Class对象(只做了第一步)
        Class c1=Student.class;//获取类的Class对象
        //第二种加载类的方式 forName()方法(做了三步,加载-链接-初始化),
//里面参数是包名.类名,会给静态变量分配空间并初始化、加载静态方法和静态块
Class c2=Class.forName("com.load.Student");//包路径
//new对象加载类
Student s3=new Student();
} } class Student{ private String name; private int age; private String sex; private static String school=method01(); static { System.out.println("类的静态初始化块!"); school="西安工业大学"; } private static String method01() { System.out.println("初始化类的静态成员变量!"); return "default"; } public Student(String name,int age,String sex){ this.name=name; this.age=age; this.sex=sex; } }

三种加载类的方式:

1. 第一种加载类的方式,只是加载类的Class对象(只做了第一步)
Class c1=Student.class;  //获取类的Class对象

多用于参数的传递
2. 第二种加载类的方式 forName()方法(做了三步,加载-链接-初始化),
 里面参数是包名.类名,会给静态变量分配空间并初始化、加载静态方法和静态块
 Class c2=Class.forName("com.load.Student"); //包路径
当加载Student类时,到第二步给成员变量分配内存空间时,要看这个类有没有基类,有基类时要先加载基类,执行一二三步,该基类若还有基类,则继续向上递归执行;

多用于配置文件,将类名定义在配置文件中。读取文件,加载类!

3.生成对象,首先会加载类,会打印实例化块和构造函数

Student s=new Student; Class c=s.getClass();

多用于对象的获取字节码的方式

 结论:同一个字节码文件(*.class)在依次程序运行过程中,只会被加载一次,不管通过哪种方式获取的Class对象都是同一个。

JVM方法区(method area)Class对象信息,static 成员变量。类加载的时候就在方法区开辟空间,一般持续到程序结束。

类加载器:

访问类的第三种方式:Student s=new Student();   Class c3=s.getClass();( //通过访问类.class(第一步)) 

System.out.println(s3.getClassLoad());          //(获取类的加载信息)   打印结果:sun.misc.Launcher$AppClassLoader@18b4aac2

 JVM的功能之一:提供类加载器加载类  

打印系统定义的类的加载器时,结果为null                                                                          System.out.println(String.class.getClassLoader());

打印AppClassLoader的父类加载器sun.misc.Launcher$ExtClassLoader@1b6d3586        System.out.println(c3.getClassLoader().getParent());

再打印ExtClassLoader的父类为null                                                                                     System.out.println(c3.getClassLoader().getParent().getParent());

因为java的jJVM是用C/C++写的,启动JVM时,本质上是一个C++程序。

BootstrapClassLoader(原生类加载器)         C:Program FilesJavajdk1.8.0_192jrelib
         是用原生代码编写(c&c++),负责加载JVM运行依赖的jar包

 可知,三个加载器的继承关系:          JVM默认提供的类加载器

          * BootstrapClassLoader(原生类加载器) C:Program FilesJavajdk1.8.0_192jrelib
             是用原生代码编写(c&c++),负责加载JVM运行依赖的jar包
                 |
          * ExtClassLoader(扩展类加载器)  加载java的扩展库        C:Program FilesJavajdk1.8.0_192jrelibext
                 |
          * AppClassLoader(应用类加载器)           CLASSPATH路径下去加载相应的字节码文件
            (SystemClassLoader)

类加载器都是通过"双亲委托模型"来加载类的,什么意思?好处是什么?
双亲委托模型:遇见一个需要加载的类,Student类理应由AppClassLoader来加载,实际上AppClassLoader先请求它的父类ExtClassLoader看能否加载Student类, ExtClassLoader在往上请求BootstrapClassLoader能否加载Student类;实际上BootstrapClassLoader无法加载Student类,ExtClassLoader也无法加载Student类,最后只能由AppClassLoader自己加载Student类,Student类就是这样加载起来的,把这种加载方式称为“双亲委托模型"


好处:是防止类被重复的加载  String str = new String();

原文地址:https://www.cnblogs.com/laurarararararara/p/11773625.html