深入理解JVM:Java类加载机制

Java类加载机制

类加载器的任务是根据类的全限定名来读取此类的二进制字节流(字节码文件)到 JVM 中,然后转换成一个与目标类对象的java.lang.Class 对象的实例。

类加载的时机

  • 隐式加载 new 创建类的实例,
  • 显式加载:loaderClass,forName等
  • 访问类的静态变量,或者为静态变量赋值
  • 调用类的静态方法
  • 使用反射方式创建某个类或者接口对象的Class对象。
  • 初始化某个类的子类
  • 直接使用java.exe命令来运行某个主类

类加载的过程

我们编写的java文件都是保存着业务逻辑代码。java编译器将 .java 文件编译成扩展名为 .class 的文件。.class 文件中保存着java转换后,虚拟机将要执行的指令。当需要某个类的时候,java虚拟机会加载 .class 文件,并创建对应的class对象,将class文件加载到虚拟机的内存,这个过程被称为类的加载

深入理解JVM:Java类加载机制_第1张图片

加载

类加载过程的一个阶段,ClassLoader通过一个类的完全限定名查找此类字节码文件,并利用字节码文件创建一个class对象。

验证

目的在于确保class文件的字节流中包含信息符合当前虚拟机要求,不会危害虚拟机自身的安全,主要包括四种验证:文件格式的验证,元数据的验证,字节码验证,符号引用验证。

准备

类变量static修饰的字段变量)分配内存并且设置该类变量的初始值,(如static int i = 5 这里只是将 i 赋值为0,在初始化的阶段再把 i 赋值为5),这里不包含final修饰的static ,因为final在编译的时候就已经分配了。这里不会为实例变量(普通的类属性如public int a;)分配初始化,类变量(静态变量)会分配在方法区中,实例变量会随着对象分配到Java中。

解析

这里主要的任务是把常量池中的符号引用替换成直接引用

初始化

类的初始化主要是初始化静态成员变量。这里是类记载的最后阶段,如果该类具有父类就进行对父类进行初始化,执行其静态代码块静态初始化成员变量。(前面已经对static 初始化了默认值,这里我们对它进行赋值)

public class Person{
  public static String name="张三";
  public static int age;
  static{
       age=20;
    System.out.println("初始化age");
  }
  public static String address;
  static{
    address="北京市";
    age=34;
  }
  public static void main(String[] args) {
         System.out.println(name);
         System.out.println(age);
         System.out.println(address);
   }
}

当java源代码转换成一个class文件后,其转换成类似下面的代码:

public class Person{
  public static String name;
  public static int age;
  public static String address;
  static{
    name="张三";
    age=20;
    System.out.println("初始化age");
    address="北京市";
    age=34;
  }
  public static void main(String[] args) {
        System.out.println(name);
        System.out.println(age);
		System.out.println(address);
   }
}

forName和loaderClass区别

  • Class.forName()得到的class是已经初始化完成的。
  • Classloader.loaderClass得到的class是还没有链接(验证,准备,解析三个过程被称为链接)的。

你可能感兴趣的:(Java,朝花夕拾-杂集,jvm,类加载机制,java)