欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java JVM-类加载机制

程序员文章站 2022-05-01 16:15:44
简单理解:JVM-类加载机制为了加深印象,防止自己一次又一次上网查阅,所以根据网上所查手动粘贴整理一下,以便个人记忆,希望大家多多指正一、什么是类加载机制?JVM把class文件加载到内存里面,并对数据进行校验、准备、解析、初始化,最终形成被JVM可以直接使用的java类型的全过程1.加载:将class文件加载在内存中。将静态数据结构(数据存在于class文件的结构)转化成方法区中运行时的数据结构(数据存在于JVM时的数据结构)。在堆中生成一个代表这个类的java.lang.Class对象...

简单理解:JVM-类加载机制

为加深印象,防止自己一次又一次上网查阅,所以把网上所查知识手动粘贴整理一下,以便个人记忆,希望大家多多指正

一、什么是类加载机制?

JVM把class文件加载到内存里面,并对数据进行校验、准备、解析、初始化,最终形成被JVM可以直接使用的java类型的全过程

Java JVM-类加载机制

1.加载:

  • 将class文件加载在内存中。
  • 将静态数据结构(数据存在于class文件的结构)转化成方法区中运行时的数据结构(数据存在于JVM时的数据结构)。
  • 在堆中生成一个代表这个类的java.lang.Class对象,作为数据访问的入口。

2.链接:

链接就是将Java类的二进制代码合并到java的运行状态中的过程。

  • 验证:确保加载的类符合JVM规范与安全。

  • 准备:为static变量在方法区中分配空间,设置变量的初始值。例如static int a=3,在此阶段会a被初始化为0,其他数据类型参考成员变量声明。

  • 解析:虚拟机将常量池的符号引用转变成直接引用。例如"aaa"为常量池的一个值,直接把"aaa"替换成存在于内存中的地址。

    • 符号引用:符号引用以一组符号来描述所引用的目标,符号可以是任何形式的字面量,只要使用时能无歧义地定位到目标即可。符号引用与虚拟机实现的内存布局无关,引用的目标并不一定已经加载到内存中。

    • 直接引用:直接引用可以是直接指向目标的指针、相对偏移量或是一个能间接定位到目标的句柄。直接引用是与虚拟机实现的内存布局相关的,如果有了直接引用,那么引用的目标必定已经在内存中存在。

3.初始化:

  • 初始化阶段是执行类构造器()方法的过程。类构造器()方法是由编译器自动收藏类中的所有类变量的赋值动作和静态语句块(static块)中的语句合并产生

  • 当初始化一个类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化

  • 虚拟机会保证一个类的()方法在多线程环境中被正确加锁和同步

  • 当范围一个Java类的静态域时,只有真正声明这个域的类才会被初始化
    例1:

public class Demo01 { public static void main(String[] args) { A a = new A(); System.out.println(a.width); } } class A{ public static int width=100; //静态变量,静态域 field static{ System.out.println("静态初始化类A"); width = 300 ; } public A() { System.out.println("创建A类的对象"); } } 

分析:
Java JVM-类加载机制

说明:

内存中存在栈、堆(放创建好的对象)、方法区(实际也是一种特殊堆)

1、JVM加载Demo01时候,首先在方法区中形成Demo01类对应静态数据(类变量、类方法、代码…),同时在堆里面也会形成java.lang.Class对象(反射对象),代表Demo01类,通过对象可以访问到类二进制结构。然后加载变量A类信息,同时也会在堆里面形成a对象,代表A类。

2、main方法执行时会在栈里面形成main方法栈帧,一个方法对应一个栈帧。如果main方法调用了别的方法,会在栈里面挨个往里压,main方法里面有个局部变量A类型的a,一开始a值为null,通过new调用类A的构造器,栈里面生成A()方法同时堆里面生成A对象,然后把A对象地址付给栈中的a,此时a拥有A对象地址。

3、当调用A.width时,调用方法区数据。

二、类初始化时机

  • 类的主动引用(一定会发生类的初始化)
    • new一个类的对象
    • 调用类的静态成员(除了final常量)和静态方法
    • 使用java.lang.reflect包的方法对类进行反射调用
    • 当虚拟机启动,java Demo01,则一定会初始化Demo01类,说白了就是先启动main方法所在的类
    • 当初始化一个类,如果其父类没有被初始化,则先初始化它父类
  • 类的被动引用(不会发生类的初始化)
    • 当访问一个静态域时,只有真正声名这个域的类才会被初始化
    • 通过子类引用父类的静态变量,不会导致子类初始化
    • 通过数组定义类的引用,不会触发此类初始化
    • 引用常量不会触发此类的初始化(常量在编译阶段就存入调用类的常量池中了)

例2:

public class Demo01 { static{ System.out.println("静态初始化Demo01"); } public static void main(String[] args) throws Exception { System.out.println("Demo01的main方法!"); System.out.println(System.getProperty("java.class.path")); //主动引用 //        new A(); //        System.out.println(A.width); //        Class.forName("com.sinosoft.test.A"); //被动引用 //        System.out.println(A.MAX); //        A[] as = new A[10]; System.out.println(B.width);//B类不会被加载 } } class B extends A { static { System.out.println("静态初始化B"); } } class A extends A_Father { public static int width=100; //静态变量,静态域    field public static final int MAX=100; static { System.out.println("静态初始化类A"); width=300; } public A(){ System.out.println("创建A类的对象"); } } class A_Father extends Object { static { System.out.println("静态初始化A_Father"); } } 

本文地址:https://blog.csdn.net/qq_41200879/article/details/108264605

相关标签: java JVM