六安网站排名优化电话,商城网站用什么做,莱芜金点子最新招工招聘启事,最新备案域名1. 类加载实例化过程 当我们编写完一个*.java类后。编译器#xff08;如javac#xff09;会将其转化为字节码。转化的字节码存储在.class后缀的文件中#xff08;.class 二进制文件#xff09;。接下来在类的加载过程中虚拟机JVM利用ClassLoader读取该.class文件将其中的字…1. 类加载实例化过程 当我们编写完一个*.java类后。编译器如javac会将其转化为字节码。转化的字节码存储在.class后缀的文件中.class 二进制文件。接下来在类的加载过程中虚拟机JVM利用ClassLoader读取该.class文件将其中的字节码加载到内存中。基于这些字节码信息创建相应的Class Object.每个类在JVM中只加载一次故而每个类都对应着一个唯一的Class对象(Class Object).这个对象包含了类的元信息metadata如类的名称、包名、父类、实现的接口、字段、方法、构造函数等。 class Objcect可以通过获取构造函数创建实例化的对象。
2. 类加载存储位置
字节码文件: 是Java源代码编译后的产物它们以二进制的形式存储在文件系统中。 所以它并不存放于JVM的结构中。Class Object:Class对象被存储在JVM的方法区Method Area中的元空间Metaspace里。实例化对象: 存放于堆内存Heap Memory
3. JVM利用classloader进行类加载和类初始化的区别
在Java中类加载Class Loading和类初始化Class Initialization是两个不同的阶段它们在类生命周期中扮演着不同的角色。下面是这两个阶段的区别
类加载Loading 通过类的全名获取类的二进制数据。将这些数据转换成方法区的运行时数据结构。在内存中生成一个代表这个类的java.lang.Class对象作为这个类的各种数据的入口。然而类的初始化即执行静态初始化代码和静态初始化块是在类加载的最后阶段初始化阶段由 JVM 自行完成的。所以我们在使用类反射如User.class 获取class对象时它是不会去执行静态代码块的。类初始化Class Initialization 类初始化广义上将它类加载过程中的最后一步只不过这一步是动态的而不是由程序启动之初就加载的只有当类被主动使用时才会发生。这个阶段会执行类的静态初始化代码在声明类变量时指定的初始值和在静态代码块中指定的代码。这个过程只会在JVM首次主动使用类时发生一次。
4. 结合第三点补充说明为什么反射中Object.class 不加载静态代码块而Class.forName(ClassName)会加载静态代码块
Object.class 和 Class.forName(ClassName) 在触发类加载和初始化方面有不同的行为这主要是因为它们使用的方式和上下文不同。
Object.class: 当你使用 Object.class 时你实际上是在引用Java的根类Object的Class对象。由于Object类是Java运行时系统的一部分并且它几乎总是在你开始执行任何Java代码之前就已经被加载和初始化了因为其他所有的类都直接或间接地继承自Object类所以当你引用Object.class时它不会再次触发Object类的加载和初始化。 静态代码块只会在类首次被主动使用时执行而由于Object类几乎总是已经在使用之前就被加载和初始化了因此通过Object.class引用它不会再次触发静态代码块的执行。 Class.forName(ClassName): Class.forName(ClassName) 是一个用于动态加载类并触发其初始化的方法。当你调用这个方法并传入一个类名作为字符串时JVM会尝试找到并加载这个类。如果类还没有被加载和初始化JVM会首先加载这个类然后触发其初始化过程这包括执行静态代码块。 Class.forName() 方法的主要用途是在运行时动态地加载和使用类而不需要在编译时就知道这个类的存在。由于它是在运行时动态加载类的所以它总是会触发类的加载和初始化过程如果类还没有被加载和初始化的话。 总结来说Object.class 不会运行静态代码块是因为Object类通常在你开始执行任何Java代码之前就已经被加载和初始化了而Class.forName(ClassName) 会运行静态代码块是因为它用于在运行时动态地加载和初始化类。
5. 关于静态代码块初始化的几个关键点
执行时机静态代码块在类被加载到JVM时执行。这通常发生在类的第一次主动使用时例如创建类的实例、访问类的静态字段或方法、反射调用类的方法等。 执行顺序如果有多个静态代码块它们将按照在源文件中出现的顺序执行。 与静态变量的关系静态变量可以在静态代码块中初始化也可以在声明时直接赋值。但是如果静态变量在声明时直接赋值那么该赋值操作会在静态代码块之前执行。 静态代码块与构造器静态代码块在构造器之前执行。这是因为静态代码块属于类级别的初始化而构造器属于对象级别的初始化。 线程安全虽然静态代码块只执行一次但在多线程环境下JVM会确保静态代码块的线程安全性即静态代码块会同步执行不会被多个线程同时访问。但是请注意静态代码块中的代码本身并不是线程安全的你仍然需要确保其中的代码在多线程环境下能够正确运行。
6. 类中的静态代码块被初始化后保存在JVM的哪里
在JVM中类中的静态代码块static code block在初始化后被执行但它们本身并不直接“保存”在JVM的某个特定区域。静态代码块中的代码逻辑在类加载时被执行一次并且其执行结果如静态变量的赋值会被存储在JVM的以下区域
方法区Method Area 类加载后静态变量包括在静态代码块中初始化的变量会被存储在方法区中的静态变量区域。静态变量属于类变量不属于对象实例的一部分只会在类加载时初始化一次。 堆内存Heap Memory 虽然静态代码块本身不直接存储在堆内存中但是静态代码块中初始化的静态对象如静态的数组、其他类的静态实例等会存储在堆内存中。这些对象通过静态变量持有引用静态变量则存储在方法区的静态变量区域中。 常量池Constant Pool 如果静态代码块中声明了static final常量并且这些常量的值在编译时就能确定即常量折叠那么这些常量会被放入类的常量池中。常量池是方法区的一部分用于存储编译期生成的各种字面量和符号引用。 需要注意的是静态代码块只是类加载过程中的一个逻辑单元用于在类加载时执行一些初始化操作。这些操作的结果如静态变量的值会被存储在JVM的相应区域中而静态代码块本身并不作为一个独立的实体被保存。当类被加载并初始化后静态代码块中的代码逻辑就完成了它的使命后续的对象创建和方法调用都不会再次执行这些代码。
7. java 类级别的初始化和对象级别的初始化的区别?
在Java中类级别的初始化和对象级别的初始化是两个不同的概念它们分别涉及类的静态部分和实例部分。以下是它们之间的主要区别
类级别的初始化 执行时机当类被JVM首次主动使用时会触发类级别的初始化。这通常发生在创建类的第一个实例、访问类的静态字段或方法、或者通过反射调用类的方法等情况。 初始化内容类级别的初始化包括执行静态代码块static blocks和初始化静态变量。静态代码块和静态变量的初始化顺序按照它们在源代码中出现的顺序进行。 执行次数类级别的初始化只会在类首次被加载到JVM时执行一次无论创建多少个类的实例静态代码块都不会再次执行。 线程安全性JVM会确保类级别的初始化是线程安全的即静态代码块会同步执行不会被多个线程同时访问。 对象级别的初始化 执行时机当创建类的实例时会触发对象级别的初始化。这通常通过调用类的构造函数来完成。 初始化内容对象级别的初始化包括执行实例初始化块instance blocks和构造函数以及初始化实例变量。实例初始化块和构造函数的执行顺序是首先执行实例初始化块按照它们在源代码中出现的顺序然后执行构造函数。 执行次数与类级别的初始化不同对象级别的初始化会在每次创建类的实例时执行。 线程安全性对象级别的初始化即构造函数的执行不是线程安全的。如果在多线程环境中创建类的实例需要确保对共享资源的访问是同步的以避免数据不一致或其他并发问题。