Java中对类的主动引用和被动引用

 

在Java代码中,有些类看上去初始化了,但其实没有。例如定义一定长度某一类型的数组,看上去数组中所有的元素已经被初始化,实际上一个都没有。

对于类的初始化,虚拟机规范严格规定了只有对该类进行主动引用时,才会触发。而除此之外的所有引用方式称之为对类的被动引用,不会触发类的初始化。


虚拟机规范严格地规定了有且仅有四种情况是对类的主动引用,即必须立即对类进行初始化。四种情况如下:

1.遇到new、getstatic、putstatic或invokestatic这4条字节码指令时,如果类没有进行初始化,则需要先触发其初始化。

(1)使用new关键字实例化对象

Java代码   收藏代码
  1. /** 
  2.  * @author Perlin.Yao 
  3.  */  
  4. public class NewClass {  
  5.   
  6.     static {  
  7.         System.out.println("NewClass init!");  
  8.     }  
  9.       
  10. }  
  11. /** 
  12.  * @author Perlin.Yao 
  13.  */  
  14. public class Initialization1 {  
  15.       
  16.     public static void main(String[] args) {  
  17.         new NewClass();  
  18.     }  
  19.   
  20. }  
  21. // 输出结果  
  22. NewClass init!  

(2)读取类的静态成员变量

 

Java代码   收藏代码
  1. /** 
  2.  * @author Perlin.Yao 
  3.  */  
  4. public class StaticAttributeClass {  
  5.       
  6.     public static int value = 1;  
  7.       
  8.     public static void staticMethod() {  
  9.         //System.out.println("staticMethod invoked");  
  10.     }  
  11.       
  12.     static {  
  13.         System.out.println("StaticAttributeClass init!");  
  14.     }  
  15.   
  16. }  
  17. /** 
  18.  * @author Perlin.Yao 
  19.  */  
  20. public class Initialization2 {  
  21.       
  22.     public static void main(String[] args) {  
  23.         // 1.读取静态变量  
  24.         int x = StaticAttributeClass.value;  
  25.     }  
  26.   
  27. }  
  28. // 输出结果  
  29. StaticAttributeClass init!  

 (3)设置类的静态成员变量

 

 

Java代码   收藏代码
  1. /** 
  2.  * @author Perlin.Yao 
  3.  */  
  4. public class Initialization2 {  
  5.       
  6.     public static void main(String[] args) {  
  7.         // 2.设置静态变量  
  8.         StaticAttributeClass.value = 2;  
  9.     }  
  10.   
  11. }  
  12. // 输出结果  
  13. StaticAttributeClass init!  

 (4)调用类的静态方法

Java代码   收藏代码
  1. /** 
  2.  * @author Perlin.Yao 
  3.  */  
  4. public class Initialization2 {  
  5.       
  6.     public static void main(String[] args) {  
  7.         // 3.调用静态方法  
  8.         StaticAttributeClass.staticMethod();  
  9.     }  
  10.   
  11. }  
  12. // 输出结果  
  13. StaticAttributeClass init!  

 

2.使用java.lang.reflect包的方法对类进行反射调用的时候,如果类没有进行初始化,则需要先触发其初始化。

Java代码   收藏代码
  1. /** 
  2.  * @author Perlin.Yao 
  3.  */  
  4. public class ReflectClass {  
  5.       
  6.     static {  
  7.         System.out.println("ReflectClass init!");  
  8.     }  
  9.   
  10. }  
  11. /** 
  12.  * @author Perlin.Yao 
  13.  */  
  14. public class Initialization3 {  
  15.       
  16.     public static void main(String[] args) throws Exception {  
  17.         Class classB = Class.forName("jvm.init.ReflectClass");  
  18.     }  
  19.   
  20. }  
  21. // 输出结果  
  22. ReflectClass init!  

 3.当一个类初始化的时候,如果发现其父类还没有初始化,则需要先对其父类进行初始化。

Java代码   收藏代码
  1. /** 
  2.  * @author Perlin.Yao 
  3.  */  
  4. public class SuperClass {  
  5.       
  6.     static {  
  7.         System.out.println("SuperClass init!");  
  8.     }  
  9.       
  10.     public static int value = 123;  
  11.   
  12. }  
  13. /** 
  14.  * @author Perlin.Yao 
  15.  */  
  16. public class SubClass extends SuperClass {  
  17.       
  18.     static {  
  19.         System.out.println("SubClass init!");  
  20.     }  
  21.   
  22. }  
  23. /** 
  24.  * @author Perlin.Yao 
  25.  */  
  26. public class Initialization4 {  
  27.       
  28.     public static void main(String[] args) {  
  29.         new SubClass();  
  30.     }  
  31.   
  32. }  
  33. // 输出结果  
  34. SuperClass init!  
  35. SubClass init!  

4.当虚拟机启动时,用户需要指定一个要执行的主类,虚拟机会先初始化这个主类

其实就是public static void main(String[] args)所在的那个类

 

下面来列举几个对类被动引用的例子:

 

1.通过子类引用父类的的静态字段,不会导致子类初始化

Java代码   收藏代码
  1. /** 
  2.  * @author Perlin.Yao 
  3.  */  
  4. public class SuperClass {  
  5.       
  6.     static {  
  7.         System.out.println("SuperClass init!");  
  8.     }  
  9.       
  10.     public static int value = 123;  
  11.   
  12. }  
  13. /** 
  14.  * @author Perlin.Yao 
  15.  */  
  16. public class SubClass extends SuperClass {  
  17.       
  18.     static {  
  19.         System.out.println("SubClass init!");  
  20.     }  
  21.   
  22. }  
  23. /** 
  24.  * @author Perlin.Yao 
  25.  */  
  26. public class NotInitialization1 {  
  27.       
  28.     public static void main(String[] args) {  
  29.         int x = SubClass.value;  
  30.     }  
  31.   
  32. }  
  33. // 输出结果  
  34. SuperClass init!  

 2.通过数组定义来引用类,不会触发此类的初始化

Java代码   收藏代码
  1. /** 
  2.  * @author Perlin.Yao 
  3.  */  
  4. public class NotInitialization2 {  
  5.       
  6.     public static void main(String[] args) {  
  7.         SuperClass[] sca = new SuperClass[10];  
  8.     }  
  9.   
  10. }  
  11. // 无任何输出  

 3.常量在编译阶段会存入调用类的常量池中,本质上没有直接引用到定义常量的类,因此不会触发定义常量的类的初始化

Java代码   收藏代码
  1. /** 
  2.  * @author Perlin.Yao 
  3.  */  
  4. public class ConstClass {  
  5.       
  6.     static {  
  7.         System.out.println("ConstClass init!");  
  8.     }  
  9.       
  10.     public static final int value = 123;  
  11.   
  12. }  
  13. /** 
  14.  * @author Perlin.Yao 
  15.  */  
  16. public class NotInitialization3 {  
  17.       
  18.     public static void main(String[] args) {  
  19.         int x = ConstClass.value;  
  20.     }  
  21.   
  22. }  
  23. // 无任何输出结果  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值