类的加载着重介绍一下一下几个步骤。
虚拟机启动时,用户需要指定一个要执行的主类(包含main()方法的那个类)
加载:加载主类
准备:为类变量分配内存并设置类变量初始值(0或NULL),如果有static final 变量(对象),准备阶段赋值 static变量(对象)。
类变量:static修饰的变量:O或NULL
static final变量:因为在定义的时候必须赋初始值,在准备阶段直接赋值。
实例变量:在对象实例化时随对象一起分配在堆中。
初始化:按顺序初始化变量和其他资源。
new关键字实例化对象;
读取或设置一个类变量(static修饰),调用类的静态方法。如果有static对象、static变量、static代码块 初始化;
如果有父类还没有初始化,需要先触发父类的初始化。
对类进行反射调用。
等等。
例如:
package test;
public class Test {
Father father2 = new Father("普通成员Father2 构造函数");
static {
System.out.println("静态块执行");
}
{
System.out.println("普通代码块执行");
}
static Father father1 = new Father("静态成员Father1 构造函数");
Father father3 = new Father("普通成员Father3 构造函数");
public Test(){
System.out.println("Test类默认构造函数调用");
}
public static void main(String[] args) {
System.out.println("第一个主类对象");
Test test1 = new Test();
System.out.println("第二个主类对象");
Test test2 = new Test();
}
}
class Father {
public Father(String s) {
System.out.println(s);
}
{
System.out.println("******father init");
}
static {
System.out.println("*******father static init");
}
}
执行结果:
静态块执行
*******father static init
******father init
静态成员Father1 构造函数
第一个主类对象
******father init
普通成员Father2 构造函数
普通代码块执行
******father init
普通成员Father3 构造函数
Test类默认构造函数调用
第二个主类对象
******father init
普通成员Father2 构造函数
普通代码块执行
******father init
普通成员Father3 构造函数
Test类默认构造函数调用
分析:
1、执行main()方法的时候先加载主类Test并初始化。
初始化的时候,对主类的静态对象、静态变量、静态代码块初始化(按顺序)。所以Test类的静态代码块、静态对象father1被初始化。(输出1-4行)
其中,静态对象father1初始化的时候,需要对类Father加载并初始化。同样,Father类初始化的时候,对静态代码块初始化。在类的加载过程中,只有内部的变量创建完,才会去执行这个类的构造方法。所有的变量初始化完,才会执行构造方法。
最后调用构造函数。
2、Test test1 = new Test();(输出6-11行)
初始化Test类,静态成员和静态代码块只进行了一次初始化。
所以只初始化Test类的普通对象和普通代码块。
3、Test test2 = new Test();(输出13-18行)
注意:
1、类的静态成员和静态代码块在类加载中是最先进行初始化的,并且只进行一次。
2、执行顺序为:
- static静态代码块和静态成员
- 普通成员
- 构造函数执行
3、类加载检查:
JVM遇到一条new指令时,首先检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载、解析和初始化过。如果没有,那必须先执行相应的类的加载过程。
相关推荐
在本文中,我们讨论了 Java 类加载器中的静态变量初始化机制,了解了静态变量的初始化顺序和类加载器的生命周期。通过对静态变量初始化机制的理解,我们可以更好地掌握 Java 语言的基础知识,并更好地应用 Java 语言...
本篇文章将详细介绍如何控制 2 个 bean 的初始化顺序,提供了多种实现方式,并分析了每种方式的优缺。 问题场景 在实际开发中,我们经常会遇到这样一个场景:2 个 bean 的初始化逻辑中有依赖关系,需要控制二者的...
在Java编程语言中,程序初始化的顺序是一个关键概念,它涉及到类加载、对象创建以及执行流程的安排。了解这些顺序对于编写高效、无错误的...在实际项目中,合理利用初始化顺序可以帮助我们优化资源加载,提高程序性能。
当我们谈论“Java类继承初始化顺序”时,涉及到的关键知识点包括构造器、成员变量的初始化、super关键字以及方法的覆盖。 首先,了解类初始化的顺序至关重要。当创建一个子类实例时,初始化过程遵循以下步骤: 1. ...
在实际开发中,理解这个初始化顺序是非常重要的,尤其是在设计复杂的类结构或者涉及单例模式、线程安全初始化等场景时。如果在构造器或初始化块中依赖其他静态或非静态成员,必须确保这些成员在需要之前已经被正确...
同时,掌握类变量初始化顺序可以避免因误解而导致的错误,特别是在多线程环境中,对静态变量的并发访问和初始化顺序的控制需要特别注意。 总之,深入理解Java的ClassLoader机制和类变量初始化顺序是提升Java编程...
### Java中类的初始化顺序详解 #### 一、概述 在Java编程语言中,类的初始化是一个非常重要的概念。类的初始化涉及到多个方面,包括静态成员变量、实例成员变量、静态初始化块、实例初始化块以及构造函数等。本文...
Java类加载初始化的过程是Java编程语言中一个重要的概念,它决定了Java类的加载和初始化顺序。在Java中,类的加载是通过类加载器(ClassLoader)来实现的。类加载器会将类的字节码文件(.class)加载到Java虚拟机...
通过以上分析,我们可以看到Java虚拟机的类加载初始化过程是一个复杂但有序的过程。理解这些基本概念对于编写高效、可靠的Java应用程序至关重要。希望本文能够帮助您更好地掌握Java虚拟机的核心机制之一:类加载初始...
总之,Java代码的初始化顺序是类加载的必然过程,涉及到静态和实例初始化块、构造函数、成员变量初始化以及继承关系的影响。这个demo是学习和理解这些概念的重要工具,通过实际操作可以加深对Java内存管理和对象生命...
1. 单个类内成员的初始化顺序:静态变量、静态初始化块、变量、初始化块、构造器。 2. 在继承关系中,子类的静态成员会在父类的非静态成员初始化之前被初始化。 3. 开发者应当注意静态成员的初始化顺序,避免在继承...
Java 初始化顺序的知识点总结: * 类变量(静态变量)和实例变量(对象变量)的区别 * 初始化顺序按照定义的顺序进行 * 静态变量的初始化顺序按照定义的顺序,并且只在第一次访问时初始化 * static 关键字不能应用...
子类 --构造器 这个输出揭示了在继承关系中类的初始化顺序: 1. **静态成员和静态初始化块**:首先,会按照父类到子类的顺序初始化静态变量和执行静态初始化块。在上面的例子中,"父类 --静态变量" 和 "子类 --静态...
综上所述,JVM的类加载器子系统是复杂且精细的,它涉及到了类的加载、验证、准备、解析和初始化等多个环节。而类加载器作为类加载过程中的关键组件,其设计使得Java应用程序能够灵活地加载和运行各种不同的类文件。...
初始化顺序方面,同一编译单元内的全局变量按照声明顺序进行初始化,但不同编译单元间的全局变量的初始化顺序是不确定的,这可能导致潜在的问题。如果全局变量之间存在依赖关系,最佳实践是重构代码以消除这种依赖。...
标题中的“全局变量初始化导致的dll加载失败工程”是一个典型的C++编程问题,涉及到动态链接库(DLL)的加载机制以及全局变量的初始化顺序。在C++编程中,全局变量的初始化顺序是一个需要深入理解的概念,尤其是在...
通过以上介绍,我们可以根据项目的需求选择合适的初始化方式,`@PostConstruct`适合简单的初始化,`CommandLineRunner`适合多个初始化步骤并控制执行顺序,而启动类中的初始化方法则更灵活,但应避免过度使用。...
类的加载和初始化顺序: - 类加载:JVM首次主动使用某个类时,会进行类加载,包括类的验证、准备和解析阶段。 - 类初始化:在类初始化阶段,静态属性的内存被分配,然后执行静态初始化块来初始化静态属性。这个过程...