Java类的加载过程

Java虚拟机的类加载

定义:将类的 .class文件中的二进制数据放到内存中,将其放在运行时数据区的方法区中。

一、过程:Java中类加载分为三个过程,分别是加载、连接、解析。

  • 加载:查找并加载类的二进制数据
  • 连接:分为三个步骤,分别为验证、准备、初始化
  1. 验证:确保被加载的类的正确性
  2. 准备:为类的静态变量分配内存,并设置默认值
  3. 解析:将类中的符号引用(例如一个方法名)转换为直接引用(指针地址等)
  • 初始化:为类的静态变量赋予正确的初始值

二、类的加载时机

JVM 规范没有强制约束类加载过程的第一阶段(加载)什么时候开始,但对于“初始化”阶段,有着严格的规定
Java 程序对类的使用分为两种:主动使用和被动使用,其中被动使用不会导致类的初始化。

  • 主动使用
  1. 创建类的实例
  2. 访问某个类或者某个接口的静态变量,或者对该静态变量赋值
  3. 调用类的静态方法
  4. 反射(如Class.forName(“com.test.Test”))
  5. 初始化一个类的子类
  6. java虚拟机启动时被表明启动的类
  7. JDK1.7开始提供的动态语言支持
  • 被动使用
    除了上面7种方式的主动使用,其他的都是被动使用(O(∩_∩)O哈哈~),也不会导致类的初始化。
一些简单的类加载例子
package com.jvm.dlassLoader;

import java.util.UUID;


/**
 *
 *  当一个常量的值并非编译期间可以确定的,那么其值就不会被放到调用类的常量池中,
 *  这是在程序运行时,会导致主动使用这个常量所在的类,显然会导致这个类被初始化。
 *
 */
public class MyTest3 {

    public static void main(String[] args) {
        System.out.println(MyParent3.str);
    }


}

class MyParent3 {
    public static final String str = UUID.randomUUID().toString();

    static {
        System.out.println("MyParent3 static code");
    }
}
package com.jvm.dlassLoader;


/**
 *
 *  对于数组实例来说,其类型是由jvm在运行期动态生成的, [Lcom.jvm.dlassLoader.MyParent4
 *  这种形式,动态生成的类型,其父类型就是Object.
 *
 *  对于数组来说,JavaDoc经常将构成数组的元素为Component,实际上就是将数组降低一个维度后的类型
 *
 *
 *  助记符
 *  anewarray:表示创建一个引用类型的(如类、接口、数组)数组,并将其引用值压入栈顶
 *  newarray:表示创建一个指定的原始类型(如int、float、char等)的数组,并将其引用值压入栈顶
 */


public class MyTest4 {

    public static void main(String[] args) {
        MyParent4 myParent4 = new MyParent4();
        System.out.println(myParent4.getClass());

        MyParent4[] myParent4s = new MyParent4[1];
        System.out.println(myParent4s.getClass());

        MyParent4[][] myParent4s1 = new MyParent4[1][1];
        System.out.println(myParent4s1.getClass());


        System.out.println(myParent4s.getClass().getSuperclass());
        System.out.println(myParent4s1.getClass().getSuperclass());

        System.out.println("=========");

        int[] ints = new int[1];
        System.out.println(ints.getClass());
        System.out.println(ints.getClass().getSuperclass());

        char[] chars = new char[1];
        System.out.println(chars.getClass());

        boolean[] booleans = new boolean[1];
        System.out.println(booleans.getClass());

        byte[] bytes = new byte[1];
        System.out.println(bytes.getClass());
    }
}

class MyParent4 {

    static {
        System.out.println("MyParent static block");
    }
}
package com.jvm.dlassLoader;


/**
 *  当一个接口在初始化时,并不要求其父接口都完成了初始化
 *  只有在真正使用到父接口的时候(如引用就扣中所定义的常量时),才会初始化
 *
 */
public class MyTest5 {

    public static void main(String[] args) {
        System.out.println(MyChild5.b);
    }
}


interface MyParent5 {
    public static Thread thread = new Thread() {

        {
            System.out.println("MyParent5 invoked");
        }
    };
}

class MyChild5 implements MyParent5 {

    public static int b = 6;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值