jvm类的初始化(三)

JVM初始化一个类包含如下步骤:

  1. 假如这个类还没有被加载和连接,程序先加载并连接该类
  2. 假如该类的直接父类还没有初始化,则先初始化其直接父类
  3. 假如类中有初始化语句,则系统依次执行这些初始化语句。

类初始化的时机:

  1. 创建类的实例:new,反射等。
  2. 调用某个类的静态方法
  3. 访问某个类或接口的静态属性
  4. 使用反射方式来强制创建某个类或接口对应的Class的对象。
  5. 初始化某个类的子类,该子类的所有父类都会被初始化。
  6. 直接使用java命令来运行某个类,当运行某个主类时,程序会先初始化该主类。

特殊情况:

  1. 对于一个final型的静态属性,如果该属性可以在编译时就得到属性值,则可认为该属性可被当成编译时常量。当程序使用编译时常量时,系统会认为这是对该类的被动使用,所以不会导致该类的初始化。
  2. 如果final类型的静态属性的值不能在编译时得到,必须等到运行时才可以确定,如果通过该类来访问该静态属性,则可以认为是主动访问使用该类,将会导致该类被初始化。
  3. 当使用ClassLoader类的loadClass方法来加载某个类时,该方法只是加载该类,并不会执行该类的初始化。当使用Class的forName静态方法才会导致强制初始化该类。
  4. 只有当程序访问的静态变量或静态方法确实在当前类或当前接口中定义时,才可以认为是对类或接口的主动使用

特殊情况1

class FinalTest1 {
    public static final int a = 3;

    static {
        System.out.println("FinalTest1 is initialization");
    }
}

public class Test1 {
    public static void main(String[] args) {
        System.out.println(FinalTest1.a);
    }
}

输出结果
3

解析:当Test1执行main方法时,FinalTest1中的a在编译时就得到属性值,故不会对FinalTest1进行初始化操作,所以不会出现FinalTest1 is initialization

特殊情况2

class FinalTest2 {
    public static final int a = new Random().nextInt(10);

    static {
        System.out.println("FinalTest2 is initialization");
    }
}

public class Test2 {
    public static void main(String[] args) {
        System.out.println(FinalTest2.a);
    }
}

输出结果
FinalTest2 is initialization
5

解析:当Test2执行main方法时,FinalTest2中的a不能在编译时得到,必须等到运行时才可以确定,故会对FinalTest2进行初始化操作,所以会出现FinalTest2 is initialization

特殊情况3

class FinalTest3 {
    static {
        System.out.println("FinalTest3 is initialization");
    }
}

public class Test3 {
    public static void main(String[] args) throws ClassNotFoundException {
        ClassLoader classLoader = ClassLoader.getSystemClassLoader();
        Class<?> clazz = classLoader.loadClass("com.api.program.activity.controller.FinalTest3");
        System.out.println("-----------------");
        clazz = Class.forName("com.api.program.activity.controller.FinalTest3");
    }
}

输出
-----------------
FinalTest3 is initialization

解析:当Test3执行main方法时,首先会执行ClassLoader加载类,然后再用class反射加载。故只有反射

特殊情况4

class Parent{
    public static final int a=new Random().nextInt(10);
    static {
        System.out.println("parent is initialization");
    }
}
class Son extends Parent{
    static {
        System.out.println("son is initialization");
    }
}
public class Test4 {
    public static void main(String[] args) {
        System.out.println(Son.a);
    }
}

输出
parent is initialization
6

解析:因为变量a未在Son,所以执行main方法不会初始化Son

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值