类的初始化研究

我们都知道java中类的生命周期包含7个阶段:加载 –> 验证 –> 准备 –> 解析 –> 初始化 –> 使用 –> 卸载
其中 验证、准备、解析 三个阶段又统称为 连接,那么在java中类的初始化情况时什么样的???在哪些情况下会触发类的初始化,个人总结了一下些情况(个人研究,可能不全)

  • 读取的 static final 不会触发类的初始化
  • 读取的static 将触发的初始化
  • 调用的static 方法 将触发的初始化
  • new 一个类将触发类的初始化
  • 使用reflect进行反射操作将触发类的初始化
  • 读取子类的 static final 不会出发类的初始化
  • 读取子类的static 字段将触发类的初始化,如果父类还未初始化过,将首先初始化父类,再初始化子类
  • 通过reflect进行反射操作子类,将会触发类的初始化,如果父类还未初始化过,将首先初始化父类,再初始化子类
  • 通过子类读取父类的static final 字段将不会触发类的初始化
  • 通过子类读取父类的static字段将会触发父类的初始化,而不会触发子类的初始化
  • new 子类对象时将触发类的初始化,如果父类还未初始化过,将首先初始化父类,再初始化子类
  • 定义类的数组将不会触发类的初始化
  • 当虚拟机启动时,将初始化化启动主类(包含有main方法的类)
  • 当一个子类初始化时,要求父类先初始化
  • 接口初始化与普通类的区别在于,接口初始化时并不要求全部父接口完成初始化,只有要用到时才会初始化(摘自深入java虚拟机)

关于接口的初始化:

接口的加载过程与类加载过程稍有不同,由于接口中不能使用static语句块,但是编译器任然会为接口生成“()”构造器,用于初始化接口中所有定义的成员变量,其与类的区别:当一个接口初始化时,类要求其父类全部都已经初始化了,但是在一个接口初始化时,并不要求其父类接口全部都完成完成了初始化,只有在真正是使用到父接口的时候才会初始化。

关于final static 修饰的字段:

static final 修饰的字段已在编译的时候就会初始化并存入类的常量池,在类准备阶段就直已经初始化了,所以在引用时,本质上并没有直接引用到类,而是直接对常量池引用,因此不会触发初始化

public class SubClass extends  SuperClass {
    static {
        System.out.println("sub class init ");
    }

    public static String sub = "sub";
    public static final String subf = "sub final";
}
public class SuperClass {
    static {
        System.out.println("super class init");
    }
    public static String sup = "super";

    public  static final String supf = "super final";

    public static String getSup() {
        return sup;
    }
}
public class Main {
    static {
        System.out.println("main init");
    }

    public static void main(String[] args) throws ClassNotFoundException {
//        System.out.println(SuperClass.supf);//读取的 static final 不会触发类的初始化,原因:static final 修饰的字段存
                                            // 放在常量池;常量在编译的时候就会存入类的常量池,在类加载的时候就直接将该值存
                                            // 入方法区的常量池中,本质上并没有直接引用到类,而是直接对常量池引用,因此不会触发初始化

//        System.out.println(SuperClass.sup); //读取的static 将触发的初始化

//        System.out.println(SuperClass.getSup());//调用的static 方法 将触发的初始化

//        new SuperClass(); //new 一个类将触发类的初始化

//        Main.class.getClass().forName(SuperClass.class.getName()); //使用reflect进行反射操作将触发类的初始化

//        System.out.println(SubClass.subf); // 读取子类的 static final 不会出发类的初始化

//        System.out.println(SubClass.sub); //读取子类的static 字段将触发类的初始化,如果父类还未初始化过,将首先初始化父类,再初始化子类

//        Main.class.getClass().forName(SubClass.class.getName()); //通过reflect进行反射操作子类,将会触发类的初始化,
                                                                    // 如果父类还未初始化过,将首先初始化父类,再初始化子类

//        System.out.println(SubClass.supf); //通过子类读取父类的static final 字段将不会触发类的初始化

//        System.out.println(SubClass.sup); //通过子类读取父类的static字段将会触发父类的初始化,而不会触发子类的初始化

//        new SubClass(); // new 子类对象时将触发类的初始化,如果父类还未初始化过,将首先初始化父类,再初始化子类

        SubClass[] subarr = new SubClass[1]; // 定义类的数组将不会触发类的初始化
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值