类的四种主动引用和三种被动引用

版权声明:https://me.csdn.net/weixin_42636552 https://blog.csdn.net/weixin_42636552/article/details/82949999

首先一个java文件从被加载到被卸载这个生命过程,总共要经历4个阶段:

加载->链接(验证+准备+解析)->初始化(使用前的准备)->使用->卸载。

其中加载(除了自定义加载)+链接的过程是完全由jvm负责的,什么时候要对类进行初始化工作(加载+链接在此之前已经完成了),jvm有严格的规定(四种情况):

1.遇到new,getstatic,putstatic,invokestatic这4条字节码指令时,加入类还没进行初始化,则马上对其进行初始化工作。其实就是3种情况:用new实例化一个类时、读取或者设置类的静态字段时(不包括被final修饰的静态字段,因为他们已经被塞进常量池了)、以及执行静态方法的时候。

2.使用java.lang.reflect.*的方法对类进行反射调用的时候,如果类还没有进行过初始化,马上对其进行。

3.初始化一个类的时候,如果他的父亲还没有被初始化,则先去初始化其父亲

4.当jvm启动时,用户指定一个要执行的主类(包含static void main(String[] args)的那个类),则jvm会先去初始化这个类。

以上4种预处理称为对一个类进行主动的引用,其余的其他情况,称为被动引用,都不会触发类的初始化。下面也举了些被动引用的例子:

/** 
 * 被动引用情景1 
 * 通过子类引用父类的静态字段,不会导致子类的初始化 
 * 
 */ 
class SuperClass{ 
  static{ 
    System.out.println("super class init."); 
  } 
  public static int value=123; 
} 

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

public class test{ 
  public static void main(String[]args){ 
    System.out.println(SubClass.value); 
  } 

} 

输出结果是:

super class init.
123

/** 
 * 被动引用情景2 
 * 通过数组引用来引用类,不会触发此类的初始化 
 * @author volador 
 * 
 */ 
public class test{ 
  public static void main(String[] args){ 
    SuperClass s_list=new SuperClass[10]; 
  } 
} 

输出结果:没输出。

/** 
 * 被动引用情景3 
 * 常量在编译阶段会被存入调用类的常量池中,本质上并没有引用到定义常量类类,所以自然不会触发定义常量的类的初始化 
 * @author root 
 * 
 */ 
class ConstClass{ 
  static{ 
    System.out.println("ConstClass init."); 
  } 
  public final static String value="hello"; 
} 

public class test{ 
  public static void main(String[] args){ 
    System.out.println(ConstClass.value); 
  } 
} 

输出结果:hello

(tip:在编译的时候,ConstClass.value已经被转变成hello常量放进test类的常量池里面了)

以上是针对类的初始化,接口也要初始化,接口的初始化跟类的初始化有点不同:

详情请见:
https://blog.csdn.net/weixin_42636552/article/details/82950118


猜你喜欢

转载自blog.csdn.net/weixin_42636552/article/details/82949999