什么时候会发生类初始化
前言
类的主动引用
如果在main()方法中去new一个子类的对象(子类继承了父类),那么JVM会自动初始化父类
由于这里是new子类(Son类),父类没有被初始化,所以JVM会自动初始化父类先
练习代码1(主动引用(new 的形式))
// 测试类什么时候会初始化
public class Test05 {
static {
System.out.println("Main类被加载");
}
public static void main(String[] args) throws ClassNotFoundException {
// 1、主动引用
// 由于这里是new子类(Son类),父类没有被初始化,所以JVM会自动初始化父类先
Son son = new Son();
}
}
class Father{
static int b = 2;
// 静态代码块
static {
System.out.println("父类被加载");
}
}
class Son extends Father{
static {
System.out.println("子类被加载");
m = 300;
}
static int m = 100;
static final int M = 1;
}
运行结果:
Main类被加载
父类被加载
子类被加载
练习代码2(主动引用(反射的形式))
// 测试类什么时候会初始化
public class Test05 {
static {
System.out.println("Main类被加载");
}
public static void main(String[] args) throws ClassNotFoundException {
// 1、主动引用
// 由于这里是new子类(Son类),父类没有被初始化,所以JVM会自动初始化父类先
// Son son = new Son();
// 反射也会产生主动引用
Class.forName("com.lwm.reflection.Son");
}
}
class Father{
static int b = 2;
// 静态代码块
static {
System.out.println("父类被加载");
}
}
class Son extends Father{
static {
System.out.println("子类被加载");
m = 300;
}
static int m = 100;
static final int M = 1;
}
结果与上面的一致
通过反射也是会产生类的主动引用,它会把所有东西加载进来(Main类被加载、父类被加载、子类被加载),这样会极大的消耗资源
类的被动引用
通过子类去调用父类的静态方法或者静态变量,不会对子类产生任何影响,子类不会被加载
练习代码1(被动引用(通过子类去调用父类的静态方法或者静态变量))
// 测试类什么时候会初始化
public class Test05 {
static {
System.out.println("Main类被加载");
}
public static void main(String[] args) throws ClassNotFoundException {
// 不会产生类的引用的方法
// 通过子类去调用父类的静态方法或者静态变量,不会对子类产生任何影响,子类不会被加载
System.out.println(Son.b);
}
}
class Father{
static int b = 2;
// 静态代码块
static {
System.out.println("父类被加载");
}
}
class Son extends Father{
static {
System.out.println("子类被加载");
m = 300;
}
static int m = 100;
static final int M = 1;
}
运行结果:
Main类被加载
父类被加载
2
练习代码2(被动引用(通过数组形式))
数组占了一个空间,开辟了5个空间(如果没被加载说明什么都没干(此时只有main类被加载))
// 测试类什么时候会初始化
public class Test05 {
static {
System.out.println("Main类被加载");
}
public static void main(String[] args) throws ClassNotFoundException {
// 不会产生类的引用的方法
// 通过一个数组
// 数组占了一个空间,开辟了5个空间(如果没被加载说明什么都没干(此时只有main类被加载))
Son[] array = new Son[5];
}
}
class Father{
static int b = 2;
// 静态代码块
static {
System.out.println("父类被加载");
}
}
class Son extends Father{
static {
System.out.println("子类被加载");
m = 300;
}
static int m = 100;
static final int M = 1;
}
运行结果:
Main类被加载
为什么会加载Main类呢?
因为当虚拟机启动,就会先初始化main方法所在的类,然后才执行 Son[] array = new Son[5];这行代码,这时没有任何类被加载,这行代码只是一个数组,它只是一个名字和一片空间而已
练习代码3(被动引用(通过调用常量形式))
// 测试类什么时候会初始化
public class Test05 {
static {
System.out.println("Main类被加载");
}
public static void main(String[] args) throws ClassNotFoundException {
// 不会产生类的引用的方法
// 调用子类的常量(常量并不会引起父类和子类的初始化)
System.out.println(Son.M);
}
}
class Father{
static int b = 2;
// 静态代码块
static {
System.out.println("父类被加载");
}
}
class Son extends Father{
static {
System.out.println("子类被加载");
m = 300;
}
static int m = 100;
static final int M = 1;
}
运行结果:
Main类被加载
1
所有的常量和类的静态变量都是在链接阶段就被赋了一个值,在链接阶段就做了,初始化的时候就已经存在了