一、 类的初始化是在类加载的最后阶段进行的.对一个进行主动引用时,才会进行此类的初始化,Java虚拟机规定只有下面四种情况下才会进行类的初始化:
1 当虚拟机执行:new getstatic putstatic invokestatic 四个字节码指令时,才会进行类的初始化.这个四种字节码指令当new一个对象,读取或设置一个静态变量,调用一个静态方法时就会产生.
2.当使用Java.lang.refelect 包进行反射调用是,如果类还没进行初始化,就会先进行初始化.
3.当对子类进行初始化时,如果他的父类还没有进行初始化,那么先对父类进行初始化.
4.Java虚拟机启动时,需要一个主函数,先对主函数类进行初始化.
因此以上四种情况,对一个类的引用称之为主动引用.
二、当对一个类进行被动引用是,虚拟机并不会对类进行初始化,以下是被动引用的情况:
1.在一个子类中进行对父类的静态变量或者静态方法的引用,此时这个子类属于被动引用,并不会对子类进行初始化.
对于静态变量或者静态方法,只有直接定义这个静态变量和静态方法的类才会被初始化.因此通过子类引用父类中定义静态变量或静态方法,只会触发父类的初始化.
如下代码:
public class SuperClass {
static{
System.out.println("父类初始化");
}
public static int s =1;
public static String getString(){
return "10";
}
}
public class SubClass extends SuperClass{
static {
System.out.println("子类进行初始化");
}
}
public class MainTest {
public static void main(String args[]){
System.out.println(SubClass.getString());
}
}
执行结果:
父类初始化
10
2 在对一个类的常量,也就是有final修饰的变量,进行引用时,并不会对此类进行初始化.常量在编译阶段会存入调用它的类常量池中,本质上没有直接引用到定义该常量的类,因此不会触发定义常量的类的初始化.如下代码:
public class SuperClass {
public final static String NAME="name";
static{
System.out.println("父类初始化");
}
public static int s =1;
public static String getString(){
return "10";
}
}
public class MainTest {
public static void main(String args[]){
// System.out.println(SubClass.getString());
System.out.println(SuperClass.NAME);
}
}
执行结果:
name
SuperClass 类没有进行初始化,这一点和引用接口中定义的常量是不同的.下面会有讲解.
3.通过数组对一个类进行引用时.
public class MainTest {
public static void main(String args[]){
// System.out.println(SubClass.getString());
// System.out.println(SuperClass.NAME);
SuperClass[] supe = new SuperClass[10];
}
}
这种情况下并不会执行对SuperClass的初始化.
三、接口的初始化
虚拟机对接口的初始化和对类的初始化是有区别的:
类初始化时,需要完成其所有父类的初始化工作,而对于它实现的接口,虚拟机并不要求其父接口全部初始化完成.
只有真正使用到父接口的时候(比如引用接口中的常量,调用接口中定义的方法)才会初始化该接口.
多说一句,使用接口的常量,其实只能在它的具体实现的子类中引用,因为在子接口中是无法使用的. 如下两个父子接口,两个常量s之间并不存在继承关系,两个s是完全不同的.
public interface SuperInterface {
int s = 0;
public void getString();
}
public interface SubInterface extends SuperInterface{
int s=1;
}
public class SubClass implements SubInterface{
@Override
public void getString() {
System.out.println(SubInterface.s);
System.out.println(SuperInterface.s);
}
public static void main(String args[]){
SubClass s = new SubClass();
s.getString();
}
}
执行结果:
SubInterface.s:1
SuperInterface.s:0
接口中定义的常量,也就是由final static 修饰的,这个和对类中定义的常量引用时,进行的初始化是不一样的.