java虚拟机是如何加载java类

以jdk1.8为例,当Java程序运行时,Java虚拟机(JVM)负责加载和执行Java类。以下是Java虚拟机加载Java类的过程:

一、类加载器子系统
Java虚拟机通过类加载器子系统来加载Java类。类加载器负责从不同的来源(例如文件系统、网络等)获取类的字节码,并将其转换为Java虚拟机可以使用的格式。

在Java虚拟机中,类加载器子系统由以下几个主要组件组成:

  1. Bootstrap ClassLoader:
    Bootstrap ClassLoader是Java虚拟机的内置类加载器,负责加载JRE核心类库(如rt.jar)和其他基础类,它是虚拟机的一部分,用于启动和初始化Java运行时环境。

  2. Extension ClassLoader:
    Extension ClassLoader负责加载Java扩展类库(如jre/lib/ext目录下的jar文件),它是Bootstrap ClassLoader的子类。

  3. System ClassLoader:
    System ClassLoader也称为Application ClassLoader,它负责加载应用程序的类,即用户自定义的类。System ClassLoader是Extension ClassLoader的子类。

当Java虚拟机需要加载一个类时,会按照以下步骤执行:

  1. 检查类是否已经被加载过,如果是,则直接返回该类的Class对象,否则继续下一步。

  2. 委托给父类加载器进行加载。父类加载器首先尝试加载该类,如果成功则返回对应的Class对象,如果失败,则将加载任务委托给其父类加载器,依次递归向上,直到Bootstrap ClassLoader。

  3. 如果父类加载器无法加载该类,则由当前的类加载器尝试加载。当前类加载器首先从搜索路径中查找该类的字节码文件,如果找到则进行加载,并返回对应的Class对象;如果找不到,则抛出ClassNotFoundException异常。

  4. 类加载器在加载类的过程中会执行一系列的安全检查和验证操作,以确保类的正确性和安全性。

需要注意的是,类加载器采用双亲委派模型(Parent Delegation Model)。即当一个类加载器接收到加载请求时,它会首先将加载任务委托给其父类加载器,只有当父类加载器无法加载时,才自行进行加载。这种层级关系可以防止重复加载和隔离不同的类定义,确保类的唯一性和一致性。

二、在Java虚拟机中,类的生命周期中的加载、验证、准备、解析和初始化是由不同的关键类来执行的。以下是每个阶段所涉及的关键类和具体描述:

  1. 加载(Loading):加载阶段是将类的字节码文件从磁盘读取到内存,并创建一个代表该类的 Class 对象。加载过程包括三个步骤:通过类的全限定名获取字节码文件的二进制数据流,解析二进制数据流并生成对应的 Class 对象,最后将 Class 对象存放在方法区中的运行时常量池中。

  2. 验证(Verification):验证阶段是确保所加载的类符合 Java 虚拟机规范。验证过程主要包括四个方面的验证:文件格式验证,验证字节码是否符合 Class 文件的规范;元数据验证,检查类的元数据信息是否一致和正确;字节码验证,分析类的字节码流是否合法,是否包含不允许的操作;符号引用验证,检查类中使用的其他类、字段和方法符号引用是否存在、可访问和匹配。

  3. 准备(Preparation)阶段:

    • 在准备阶段,为类的静态变量分配内存,并设置默认初始值。静态变量包括基本类型和对象引用类型。
    • JVM 会在方法区为每个类的静态变量分配内存空间,并将其初始化为对应类型的默认值。例如,int 类型的静态变量会被初始化为 0,对象引用类型的静态变量会被初始化为 null。
    • 注意,此时并不会执行静态代码块中的代码,只是为静态变量分配内存空间并赋予默认值。
  4. 解析(Resolution)阶段:

    • 解析阶段是将编译阶段生成的符号引用转换为直接引用,以便能够在之后的代码中进行访问和调用。
    • 对于类或接口的解析,将类或接口的全限定名解析为对应的直接引用,用于后续的字段和方法访问。
    • 对于字段解析,将类中的字段符号引用解析为字段在内存中的直接地址,以便可以获取或设置字段的值。
    • 对于方法解析,将方法的符号引用解析为方法在内存中的直接地址,以便可以调用方法的代码。
  5. 初始化(Initialization)阶段:

    • 初始化阶段是对类进行初始化的过程,包括静态变量的赋值和执行静态代码块中的代码。
    • 在初始化阶段,按照声明顺序依次执行静态变量的赋值操作,并执行静态代码块中的代码。
    • 静态变量的赋值可以是直接赋值或通过静态代码块来完成。这些赋值操作可以依赖于其他类的加载、验证和准备等操作。
    • 需要注意的是,初始化阶段只会触发一次,且是线程安全的。JVM 会保证在多线程环境下只有一个线程执行初始化操作。

总结起来,准备阶段为静态变量分配内存并设置默认初始值,解析阶段将符号引用转换为直接引用,初始化阶段对静态变量进行显式赋值并执行静态代码块。这三个阶段共同构成了类的初始化过程,确保类在使用之前被正确地初始化。

三、懒加载

类加载过程是懒加载的,即只有在需要使用某个类时才会进行加载。一般情况下,类在首次使用时才被加载。此外,Java虚拟机还提供了动态类加载的机制,可以在运行时动态加载、链接和实例化类。这种延迟加载的机制可以提高程序的性能和资源利用率。

一般情况下,Java 虚拟机采用了以下两种懒加载策略:

  1. 类的初始化阶段:在类的初始化阶段,静态变量会被赋予初始值并执行静态代码块。这是类加载过程中的最后一个步骤,且只会触发一次。因此,直到首次访问该类的静态变量或静态方法,或者创建该类的实例对象时,类的初始化阶段才会启动。

  2. 类的连接阶段中的解析阶段:在类的连接阶段,类的符号引用会被解析为直接引用。解析阶段可能需要依赖其他类的加载、验证和准备等操作。因此,在第一次使用一个类的时候,如果存在对其他类的引用,那么这个类的解析阶段就会被触发。

除了常规的类加载机制,Java 虚拟机还提供了动态类加载的机制,允许在运行时根据需要动态加载、链接和实例化类。这为应用程序提供了更大的灵活性和动态性。通过使用反射机制,可以在运行时根据类名加载相应的类,并执行相关操作。

动态类加载的典型场景包括插件系统、模块化开发以及动态扩展功能等。它使得应用程序能够在运行时根据需要加载和使用特定的类,而不需要在编译时就明确引入和依赖这些类。

总结起来,Java 类加载过程是懒加载的,即只有在首次使用某个类时才会进行加载。这种延迟加载的机制可以提高程序的性能和资源利用率。此外,Java 虚拟机还提供了动态类加载的机制,可以在运行时动态加载、链接和实例化类,为应用程序提供更大的灵活性和动态性。

四、动态类加载

当谈及动态类加载时,Java提供了反射机制来实现动态加载、链接和实例化类。通过反射,可以在运行时根据类名加载相应的类,并在内存中创建该类的对象。

下面是动态类加载的一般步骤:

  1. 获取类加载器(ClassLoader):首先需要获取一个类加载器对象,它负责将字节码文件加载到内存中。Java中有几种常用的类加载器,如系统类加载器(AppClassLoader)、扩展类加载器(ExtClassLoader)和启动类加载器(BootstrapClassLoader)等。可以使用Class类的getClassLoader()方法或者调用特定类加载器的相关方法来获取类加载器对象。

  2. 加载类:利用类加载器的loadClass()方法,提供要加载的类的全限定名,从而加载指定的类。例如,使用系统类加载器加载类的代码如下:

    ClassLoader classLoader = ClassLoader.getSystemClassLoader();
    Class<?> myClass = classLoader.loadClass("com.example.MyClass");
    
  3. 链接类:加载类后,会进行类的链接过程,包括验证、准备和解析阶段。这些过程确保被加载的类满足Java虚拟机规范,并将符号引用转换为直接引用。

  4. 实例化对象:使用反射机制,可以通过类的newInstance()方法或者Constructor类的newInstance()方法来创建类的实例对象。例如,使用无参构造函数创建类的实例对象的代码如下:

    Object myObject = myClass.newInstance();
    

通过动态类加载,可以在程序运行时根据需要加载和使用各种类。这对于编写插件化系统、实现动态扩展功能以及模块化开发等场景非常有用。它使得应用程序能够根据需要加载外部类库或者用户自定义的类,并在运行时动态地与这些类进行交互。

需要注意的是,动态类加载可能会引入一些安全风险,因为它允许加载未知的类并执行其中的代码。因此,在使用动态类加载时,需要谨慎处理来确保安全性和可靠性。

最近白嫖了一个chatgpt的学习网站,分享给大家欢迎来到GPT (yantegpt.cn)

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值