什么是Java类装载机制?

Java类装载机制指的是JVM如何加载和查找类的过程。在Java程序运行过程中,JVM需要定位并加载需要使用的类文件,Java类装载机制便是完成这个过程的。

Java 类装载有五个过程:加载、验证、准备、解析和初始化。以下是Java类装载的详细使用攻略。

1. 加载

加载是指将类的字节码数据加载到内存中,并为之创建一个 java.lang.Class 对象。加载阶段需要执行如下三个过程:

  • 通过类的全名获取定义此类的二进制字节流。
  • 将字节流所代表的静态存储结构转化为方法区的运行时数据结构。
  • 在内存中生成一个 java.lang.Class 对象,作为方法区这个类的各种数据的访问入口。

2. 校验

校验是指对加载的类文件进行验证,确保符合JVM规范和应用规范。校验阶段的主要任务就是进行以下四个检查:

  • 文件格式的验证:检查class字节码的格式是否合法。
  • 元数据的验证:对类自身信息进行语义分析,保证不存在不符合Java语言规范的元数据信息。
  • 字节码验证:通过数据流检查和控制流检查等方式,确定代码语义是合法的、符合逻辑的。
  • 符号引用验证:保证解析动作能正确执行。

3. 准备

准备是指为类的静态变量分配内存并赋予初始值的过程。这些变量所使用的内存都将在方法区中进行分配。注意,这时候进行默认初始化,所以不会对类的静态变量进行显示赋值。

4. 解析

解析是Java将类的二进制数据中的符号引用转换为直接引用的过程。换而言之,就是虚拟机将常量池中的符号引用替换为直接引用的过程。解析一般发生在以下情况:

  • 调用类的静态方法或属性时,解析类获得程序要加载的对象。
  • 常量池中的符号引用转变为直接引用。

5. 初始化

初始化是类装载的最后一个阶段,也是真正意义上类准备开始执行的阶段。初始化阶段是执行类构造器()方法的过程,()方法由编译器自动收集类中所有类变量的赋值动作和静态代码块中的语句合并产生的。当构造器运行时,初始化会按照程序员指定的顺序(即静态变量定义的顺序)对静态变量进行初始化。详细的执行顺序可以参见JLS,此处不作赘述。

至此,Java类装载机制的所有过程都分析完毕。下面通过两个示例来详细说明Java类装载机制的实现过程。

示例一:动态代理类装载和执行

我们通过动态代理示例看看一个类的初始化过程。在Java中,动态代理技术是很常用的,可以通过动态代理实现对象的远程调用等。下面是一个简单的动态代理示例代码。

public interface HelloService {
    void sayHello(String name);
}

public class HelloServiceImpl implements HelloService {
    @Override
    public void sayHello(String name) {
        System.out.println("Hello, " + name);
    }
}

public class HelloProxy implements InvocationHandler {
    Object target;

    public HelloProxy(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Before Method Invoke");
        Object result = method.invoke(target, args);
        System.out.println("After Method Invoke");
        return result;
    }
}

public class Main {
    public static void main(String[] args) {
        // 创建被代理对象
        HelloService helloService = new HelloServiceImpl();
        // 创建代理对象
        HelloService proxy = (HelloService) Proxy.newProxyInstance(
                HelloService.class.getClassLoader(),
                new Class[]{HelloService.class},
                new HelloProxy(helloService)
        );
        // 调用方法
        proxy.sayHello("world");
    }
}

在运行该示例过程中,Java类装载机制的过程如下:

  1. 首先加载 HelloService 接口。由于该接口并没有任何实现,所以Java只将其字节码加载到内存中,不会进行进一步的校验、准备和初始化操作。
  2. 加载 HelloServiceImpl 类,由于该类实现了 HelloService 接口,所以在进行加载后,Java会进行校验、准备、初始化等操作并生成 HelloServiceImpl 类的对象。
  3. 加载 HelloProxy 类,由于该类实现了 InvocationHandler 接口,所以在加载后,Java会进行校验、准备、初始化等操作,并生成 HelloProxy 类的对象。
  4. Main 类中,先创建了 HelloServiceImpl 的一个实例,通过JVM方法Proxy.newProxyInstance()获取 HelloService 的一个代理对象。代理对象的实例化过程完全依赖于动态实现,所以需动态生成字节码。Java会先加载HelloProxy 类,由于HelloProxy 实现了InvocationHandler 接口,这时 Java会将该对象转化为字节码,在运行时动态生成代理类。这个过程比较常见,前几个步骤详见前面的分析内容。代理类实现了 HelloService接口,并将 HelloProxy 实例作为目标对象传递进去,代理对象转化为了默认实现的 HelloService 接口,以此完成了代理关系的建立。

整个过程中,Java类装载机制主要用到了对 HelloServiceImplHelloProxy 和代理类的加载、校验、准备和初始化等过程,我们可以清晰地在代码执行过程中看到加载类(使用 ClassLoader等类),校验类(字节码格式是否正确),运行静态代码块(初始化类),以及动态生成代理类等过程。

示例二:静态变量初始化

下面通过一个静态变量初始化的示例来看看在Java类装载机制中的实现过程。

public class StaticTest {
    private static int num = 1;
    private static final String s = "Hello, world";

    static {
        System.out.println("静态代码块。。。");
        num = 2;
    }

    public static void main(String[] args) {
        System.out.println(Parent.num);
        System.out.println(Parent.s);
    }
}

在运行该示例过程中,Java类装载机制的过程如下:

  1. 首先加载 StaticTest 类文件。
  2. 在加载静态变量 num 时,执行赋值操作,并将赋值结果2存储到内存中。当第二次访问时,直接从内存中取值输出。
  3. 在加载静态变量 s 时,会因为 sfinal,这时候赋值操作会直接跳过。在静态代码块中将 num 的值设置为2。

整个过程中,Java类装载机制主要用到了对 StaticTest 类的加载、静态变量nums 的赋值操作,静态代码块最后对 num 的赋值操作。我们根据代码实际执行过程,可以看到Java类装载机制对于静态变量赋值等操作的处理过程。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:什么是Java类装载机制? - Python技术站

(0)
上一篇 2023年5月11日
下一篇 2023年5月11日

相关文章

  • jsp页面调用applet实现人民币的大小写转换

    下面是jsp页面调用applet实现人民币的大小写转换的完整攻略,包含以下几个步骤: 1. 编写Java Applet代码 Java Applet是一个嵌入到HTML文档中的Java程序,具有跨平台性和安全性。Applet中的代码需继承Applet类,实现init()、paint()等方法。以下是一个简单的Java Applet代码示例,用于实现人民币金额大…

    Java 2023年6月15日
    00
  • springboot 自定义权限标签(tld),在freemarker引用操作

    下面是完整攻略: 1. 首先创建Spring Boot项目 可以使用Spring Initializr创建一个新的Spring Boot项目,选择Web和Freemarker作为依赖项。 2. 添加依赖项 在pom.xml文件中添加以下依赖项: <dependency> <groupId>org.springframework.boo…

    Java 2023年6月15日
    00
  • Hibernate批量处理海量数据的方法

    下面是详细讲解Hibernate批量处理海量数据的方法的完整攻略: 前言 在企业级应用程序中,通常需要处理大量的数据,而批量数据处理更是必不可少的一环。Hibernate提供了各种机制来批量处理海量的数据。下面我们将详细介绍这些机制以及如何使用它们来处理大量的数据。 Session缓存 为什么需要Session缓存 Session缓存是Hibernate中非…

    Java 2023年5月20日
    00
  • Java如何实现定时任务

    Java中实现定时任务的方式有多种,主要包括使用Timer和TimerTask类、使用ScheduledExecutorService接口、使用cron表达式和使用Quartz框架。 使用Timer和TimerTask类 Timer是一种简单的任务调度器,用于按照指定的时间间隔执行任务。TimerTask是Timer中的任务,可以继承TimerTask类并重…

    Java 2023年5月26日
    00
  • java中maven下载和安装步骤说明

    下面是关于Java中Maven下载和安装步骤的完整攻略。 简介 Maven是一款用于项目管理和自动化构建的工具。它能够自动化构建、测试、打包Java应用程序,并能够管理应用程序的依赖关系及其版本。在Java开发过程中,Maven是极其重要的工具之一。 下载 在官方网站(https://maven.apache.org/download.cgi) 下载最新版本…

    Java 2023年5月19日
    00
  • 浅谈Springboot之于Spring的优势

    浅谈Spring Boot之于Spring的优势攻略 简介 Spring Boot是一种基于Spring框架的快速开发框架。相对于Spring框架,Spring Boot可以更快速地构建和部署Spring应用程序。本文将介绍使用Spring Boot构建应用程序相对于使用Spring框架构建的优势,并提供一些示例。 优势 快速构建应用程序 Spring Bo…

    Java 2023年5月15日
    00
  • 微信小程序中多个页面传参通信的学习与实践

    下面是 “微信小程序中多个页面传参通信的学习与实践”的完整攻略: 一、背景概述 在微信小程序开发中,经常需要跨页面进行参数传递。如何实现跨页面传参通信是小程序开发必备技能之一。 二、传参方式 微信小程序中,实现多个页面之间传参通信的方式有很多,常用的有以下方式: 1. 链接传参 在“页面跳转”中,使用wx.navigateTo或wx.redirectTo进行…

    Java 2023年5月23日
    00
  • JDBC三层架构深入刨析

    JDBC(Java Database Connectivity)三层架构指的是将数据库操作分成三个独立的层次:JDBC API、JDBC驱动程序和数据库本身。下面分三个部分详细解释每个层次的作用和相互之间的关系: JDBC三层架构 JDBC API JDBC API提供了一系列的类和接口,用于在Java程序中对数据库进行操作,通过JDBC API来实现Jav…

    Java 2023年5月20日
    00
合作推广
合作推广
分享本页
返回顶部