触发类的初始化(附实例)

在Java中,类的初始化(即执行类的<clinit>()方法,该方法是由编译器自动收集类中的所有类变量的赋值动作和静态代码块static{}中的语句合并产生的)通常会在以下几种情况下被触发:

  1. 创建类的实例:当使用new关键字创建类的实例时,如果该类还没有被初始化,则会先触发该类的初始化。

    class MyClass {  
        static {  
            System.out.println("MyClass is being initialized.");  
        }  
    }  
      
    public class Test {  
        public static void main(String[] args) {  
            MyClass obj = new MyClass(); // 触发MyClass的初始化  
        }  
    }
  2. 访问类的静态变量(除了被final修饰的常量,且常量在编译期就能确定其值的情况):如果尝试访问类的静态变量,并且这个类还没有被初始化,那么会先触发该类的初始化。

    class MyClass {  
        static int staticVar = 10; // 注意:这里不是编译时常量  
        static {  
            System.out.println("MyClass is being initialized.");  
        }  
    }  
      
    public class Test {  
        public static void main(String[] args) {  
            System.out.println(MyClass.staticVar); // 触发MyClass的初始化  
        }  
    }
  3. 访问类的静态方法:当类的静态方法被调用时,如果该类还没有被初始化,则会先触发该类的初始化。

    class MyClass {  
        static {  
            System.out.println("MyClass is being initialized.");  
        }  
      
        public static void staticMethod() {  
            System.out.println("Static method called.");  
        }  
    }  
      
    public class Test {  
        public static void main(String[] args) {  
            MyClass.staticMethod(); // 触发MyClass的初始化  
        }  
    }
  4. 使用反射调用类的方法:通过反射(如Class.forName("com.example.MyClass"))来强制对类进行加载时,如果这个类还没有被初始化,则会触发该类的初始化。注意,Class.forName()方法会触发类的加载、链接和初始化三个阶段。

    class MyClass {  
        static {  
            System.out.println("MyClass is being initialized.");  
        }  
    }  
      
    public class Test {  
        public static void main(String[] args) throws ClassNotFoundException {  
            Class.forName("MyClass"); // 触发MyClass的初始化  
        }  
    }
  5. 初始化一个类的子类:如果子类被初始化,而父类还没有被初始化,那么在初始化子类之前会先初始化父类。

    class ParentClass {  
        static {  
            System.out.println("ParentClass is being initialized.");  
        }  
    }  
      
    class ChildClass extends ParentClass {  
        static {  
            System.out.println("ChildClass is being initialized.");  
        }  
    }  
      
    public class Test {  
        public static void main(String[] args) {  
            new ChildClass(); // 先触发ParentClass的初始化,然后触发ChildClass的初始化  
        }  
    }
  6. JVM启动时标明的启动类:JVM在启动时,会通过命令行参数指定一个主类(包含main方法的类),此时会触发该主类的初始化。

  7. 使用类加载器动态加载类:在使用类加载器(ClassLoader)动态加载类时,如果这个类还没有被初始化,则会触发该类的初始化。

需要注意的是,类的初始化只会被执行一次,因为<clinit>()方法是同步的(synchronized),并且在类加载到JVM的过程中只会被调用一次。此外,静态初始化块(static blocks)按照它们在类中出现的顺序执行,并且只执行一次。

还需注意的是,对于final修饰的静态常量,如果它们在编译时就能确定其值,那么这种常量的访问不会触发类的初始化。这是因为这些常量在编译时就已经被替换成了具体的值,而在运行时无需再引用到定义它们的类。

  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值