首页 > 编程语言 >Java的类加载顺序

Java的类加载顺序

时间:2023-09-28 10:35:39浏览次数:22  
标签:顺序 Java 代码 System println out 加载

1.类加载器

Java虚拟机的类加载过程是由类加载器(ClassLoader)来实现的。类加载器负责将类装载到内存中,并为其创建一个Class对象。Java虚拟机定义了三种类加载器,分别为Bootstrap ClassLoader、Extension ClassLoader、System ClassLoader,它们按照层次关系进行组织,而且每个类加载器都有自己独立的命名空间,保证了不同类加载器之间的隔离性。

2. 加载阶段

类加载过程的第一阶段是加载(Loading),即通过类加载器读取.class文件中的二进制字节流,并将其转换成Java虚拟机中的Class对象。在这个阶段,Java虚拟机将会检查类文件的格式、语义等内容,确保其符合Java规范,否则将抛出ClassFormatError等异常。

3. 验证阶段

在加载完成后,Java虚拟机会对类进行验证(Verification),以确保它的字节码是正确、安全且符合规范的。这个阶段主要有四种验证方式:文件格式验证、元数据验证、字节码验证和符号引用验证。

4. 准备阶段

在验证通过后,Java虚拟机会为类分配内存空间,并进行默认初始化(Prepare),即将类变量分配内存并初始化为二进制零值。这个过程中不会涉及任何Java代码执行,只是简单地为类变量赋予一些初始值。

5. 解析阶段

解析(Resolution)是Java虚拟机将符号引用替换为直接引用的过程。在Java程序中,调用方法或访问对象时通常使用符号引用,需要在运行时将其解析成直接引用才能执行相应的操作。

6. 初始化阶段

当类被加载并初始化后,Java虚拟机会执行其静态初始化器(clinit)中的Java代码。静态初始化器包含了对类中所有静态变量进行赋值操作的Java代码块,它们按照类定义时的顺序依次执行。如果在静态初始化器中发生异常,则该类将被视为无法正确初始化,不允许被使用。

类加载过程总结

Java类加载过程是一个复杂的过程,它涉及到类加载器、运行时数据区等多个方面,并且在不同的阶段都需要完成各种任务,如文件格式验证、元数据验证、符号引用解析等。了解这些过程可以帮助Java开发者更好地理解Java虚拟机的内部实现机制,从而编写出更加高效和优秀的Java代码。

问题:

Q: Java中有哪些类加载器?

A: Java中有三种类加载器:Bootstrap ClassLoader()、Extension ClassLoader和Application ClassLoader。

1)Bootstrap ClassLoader(启动类加载器):由C++编写,负责加载Java运行环境(JRE)核心库,例如java.lang包等。它是JVM的内置类加载器,在JVM启动时就会被初始化。

2)Extension ClassLoader(扩展类加载器):用来加载Java扩展库,位于JRE的/lib/ext目录下,或者通过java.ext.dirs系统变量指定的其他目录中。

3)Application ClassLoader(应用程序类加载器):用来加载应用程序路径上的类,也称为系统类加载器。它是ClassLoader类的子类,通常是由Java应用程序创建的默认类加载器。

 

Q: 类加载器的双亲委派模型是什么?

A: 类加载器的双亲委派模型是指当一个类加载器需要加载一个类时,它首先会将这个任务委托给它的父类加载器去完成,如果父类加载器无法加载,则再由自己来尝试加载。

 

Q: 如何打破类加载器的双亲委派模型?

A: 可以使用线程上下文类加载器(Thread Context ClassLoader)来打破类加载器的双亲委派模型。

Q: 类加载器的缓存机制是什么?

A: 类加载器的缓存机制是指当一个类被某个类加载器加载后,该类及其依赖的类将被缓存到该类加载器中,以供后续使用。

Q: 如何自定义类加载器?

A: 可以通过继承ClassLoader类并重写findClass()方法来自定义类加载器。通常情况下,自定义类加载器会从指定的路径或者网络地址上加载字节码文件。

Q: 什么是热部署(HotSwap)?怎样实现Java代码的热部署?

A: 热部署是指在不停止Java应用程序的情况下,动态地替换或更新Java类或资源文件。实现Java代码的热部署可以使用一些工具,如JRebel、DCEVM等。这些工具通常通过改变类加载器的行为,使得修改后的Java类能够被重新加载到JVM中。

public class ParentClass {
    
    public ParentClass() {
        System.out.println("我是父构造器");
    }

    static {
        System.out.println("我是父静态代码块1");
    }

    static {
        System.out.println("我是父静态代码块2");
    }

    {
        System.out.println("我是父代码块1");
    }

    private int p1 = getValue();

    {
        System.out.println("我是父代码块2");
    }

    private int getValue() {
        System.out.println("我是父成员变量p1");
        return 1;
    }

    private static int getValue2() {
        System.out.println("我是父静态成员变量p2");
        return 1;
    }

    private static int p2 = getValue2();
}
public class ChildClass extends ParentClass {
    
    private int c1 = getValue();

    private static int c2 = getValue2();

    public ChildClass() {
        System.out.println("我是子构造器");
    }

    static {
        System.out.println("我是子静态代码块1");
    }

    static {
        System.out.println("我是子静态代码块2");
    }

    {
        System.out.println("我是子代码块1");
    }

    {
        System.out.println("我是子代码块2");
    }

    private int getValue() {
        System.out.println("我是子成员变量c1");
        return 1;
    }

    private static int getValue2() {
        System.out.println("我是子静态成员变量c2");
        return 1;
    }

    public static void main(String[] args) {
        ChildClass childClass = new ChildClass();
    }
}

 

我是父静态代码块1
我是父静态代码块2
我是父静态成员变量p2
我是子静态成员变量c2
我是子静态代码块1
我是子静态代码块2
我是父代码块1
我是父成员变量p1
我是父代码块2
我是父构造器
我是子成员变量c1
我是子代码块1
我是子代码块2
我是子构造器

 

结论:

先执行父类的静态变量、代码块(哪个在前哪个先执行)---> 再执行子类的静态变量、代码块(哪个在前哪个先执行)

--->再执行父类的普通变量、代码块(哪个在前哪个先执行)--->再执行父类的构造器

--->再执行子类的普通变量、代码块(哪个在前哪个先执行)--->再执行子类的构造器

 

标签:顺序,Java,代码,System,println,out,加载
From: https://www.cnblogs.com/chuhecc/p/17735124.html

相关文章

  • Java基础之变量
    一、Java中的变量1、什么是变量:变量就是存储数据的容器,是在内存中的一块存储空间,用来临时存储一个经常发生改变的数据。之所以是临时存储,是因为所有的计算机设备运行时的内存资源是非常有限的,所以需要不断的将不使用的数据清理。2、Java种数据的类型:变量是用来存储数据的,而数......
  • Java序列serialVersionUID字段
    Spring框架默认使用Java的序列化机制,也就是说,Spring默认使用Java的内置序列化器。Java的序列化机制中,每个序列化的对象都有一个serialVersionUID字段,这个字段用来标识序列化对象的版本。Java的序列化机制是这样的:当一个对象被序列化时,Java会先检查对象的类是否有一个名为"serialV......
  • 一文搞懂Java异步编程之FutureTask(转)
    背景Java异步编程的在实际开发中经常被用到,那么异步任务执行结束如何将结果通知到主线程或者其他任务呢?本文不探讨JUC包下的各类锁实现实现的任务同步或者通知。一、Thread狭隘的讲Java创建线程的方式只有一种,就是newThread实例。Thread本身是Runnable的实现并且它定义了Runna......
  • JAVA代码使用JNI的方式调用C/C++动态库
    JNI(javanativeinterface),通过JNI的方式调用动态库步骤比较麻烦,不用额外引入依赖,对java项目工程依赖侵入为0,类中含有native描述的方法都会与动态库去一一映射,能通过System.load()函数去加载动态库,这种方式主要使用的场景是java写好类(一般不是接口),让C或者C++去实现......
  • Java之包装类的算法小题的练习
     算法小题练习一:需求:键盘录入一些1~10日之间的整数,并添加到集合中。直到集合中所有数据和超过200为止。代码示例:publicclassTest1{publicstaticvoidmain(String[]args){/*键盘录入一些1~10日之间的整数,并添加到集合中。直到集合中所有数据和超......
  • 无涯教程-JavaScript - CHAR函数
    描述CHAR函数返回由数字指定的字符。使用CHAR将可能从其他类型的计算机上的文件中获得的代码页码转换为字符。语法CHAR(number)争论Argument描述Required/OptionalNumber1到255之间的数字,指定所需的字符。该字符来自Windows环境的ANSI字符集。RequiredNotes如......
  • Java for循环:编程新手的必备技能
    Java for循环和增强的for循环是一种控制流语句,它提供了一种紧凑的方法来迭代值范围。循环重复遍历代码,直到满足特定条件为止。在此期间,Java for循环具有不同类型。for循环增强for循环或foreachfor循环for循环是3个表达式的组合,需要理解才能有效地使用for循环。初始化表达式初......
  • JavaScript解密日记5
    引言:在从事JAVA工作的第五个年头,突然开始对js加密js解密感兴趣。开始了探索的路程1.JavaScript基础知识:JavaScript是一种用于Web开发的脚本语言,它包括以下基础概念:变量(Variables):用于存储数据的容器,可使用var、let或const关键字声明。数据类型(DataTypes):包括数字、字符串、布......
  • java的jdk配置环境变量
    安装JDK选择安装目录安装过程中会出现两次安装提示。第一次是安装jdk,第二次是安装jre。建议两个都安装在同一个java文件夹中的不同文件夹中。(不能都安装在java文件夹的根目录下,jdk和jre安装在同一文件夹会出错)如下图所示 1:安装jdk随意选择目录只需把默认......
  • java.net.ConnectException: Connection refused: no further information
    java.net.ConnectException:Connectionrefused:nofurtherinformation atsun.nio.ch.SocketChannelImpl.checkConnect(NativeMethod)~[na:1.8.0_91] atsun.nio.ch.SocketChannelImpl.finishConnect(SocketChannelImpl.java:717)~[na:1.8.0_91] atio.netty.channe......