JVM(三)初始化

字节码指令和符号引用、直接引用

1.主动引用和被动引用 

  主动引用:虚拟机规定只有满足四个情况的的情况下,才会进行主动引用。
    被动引用:除过四种情况的引用是被动引用。
     只有主动引用才会初始化

2.通过子类调用父类的静态字段,是被动引用,不会让初始化子类,只会初始化父类。

对于静态字段,只有直接定义这个字段的类会才会被初始化,因此,通过子类调用父类的静态字段,只会让父类初始化,子类不会初始化  

 class Father {
  public static int age = 54;
  static {
   System.out.println("父类被初始化");
  }
 }
 class Child extends Father{
  static {
   System.out.println("子类被初始化");
  }
 }
 class Test{
  public static void main(String args[]){
   syso(Child.g=age);
  }
 }
 输出:父类被初始化     33

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

  对于final对象,考虑编译阶段是否是符号引用还是直接引用

class Const{
  public static final int String name = "常量";
  static{
    syso("初始化Const类");
  }
 }
class test{
  public static void main(String args[]){
    syso(Const.name);
  }
}
 输出:常量
 虽然在程序中引用了Const类的常量,但是在编译阶段将此常量的值“常量”存储到了test类的常量池中,对Const常量的引用实际转化成了对自身常量池的引用。两个类在编译之后就不会存在联系了。

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

class Const{
 public static final int String name = "常量";
static{
syso("初始化Const类");
 }
}
class test{
public static void main(String args[]){
Const sonst[] = new Const[5];
}
}
 输出  不输出任何内容
在这段代码里面触发了另一个名为“LLConst”的类的初始化,他是一个由虚拟机自动生成、直接继承与java.lang.Object的子类,创建动作有字节码指令newarray触发,很明显,这是由一个对数组引用
 类型的初始化,而该数组只包含了一个队Const的引用,并没有对其进行初始化,如果加入实例化数组里面的Const对象,就会触发
class test{
public static void main(String args[]){
Const sonst[] = new Const[5];
 for(Const s: sonst){
s = new Const();
}
 }
输出:Const被初始化 

5.接口和类在初始化的不同:   

  接口也有初始化的过程,上面的代码中都是用静态语句块的输出初始化信息的,在接口中不能使用“static{}”语句块,但编译器仍然会为接口生成<clinet>类构造器用于初始化接口定义的成员变量;
  当一个类在初始化时,要求其父类全部已经初始化过了,但是一个接口在初始化时,并不要求其父接口全部完成了初始化,只有真正使用父接口的时候(如引用接口定义的常量),才会初始化该父类接口。

 

posted @ 2018-11-15 17:20  弄潮儿儿  阅读(277)  评论(0编辑  收藏  举报