类初始化
每个类或者接口必须在首次使用时初始化。java虚拟机会在6种情况下初始化一个类对象,这六种情况称为主动使用,分别是:
l 创建类的新实例
l 调用类中声明的静态方法
l 操作类或接口中声明的非常量静态字段
l 调用Java API中特定的反射方法
l 初始化一个类的子类
l 制定一个类作为Java虚拟机启动时的初始化类
任何一个类的初始化都要求它的所有祖先类(非祖先接口)预先被初始化,而接口的初始化则不需要祖先接口预先被初始化。
初始化一个类包含两个步骤:
1.如果类存在直接超类的话,且直接超类还没有被初始化,就先初始化直接超类
2.如果类存在一个初始化方法,就执行此方法
接口初始化只需一个步骤:
如果该接口存在一个初始化方法的话,就执行此方法
被动使用
使用一个非常量的静态字段(方法)只有当类或者接口的确声明了这个字段(方法)时才是主动使用。比如,class A中有个非常量静态字段x,class B继承A,那么当使用B.x的时候,不会初始化B类,只会初始化A类
如果一个字段既是static的,又是final的,并且使用一个编译时常量表达式初始化,是用这样的字段,就不是对声明该字段的类的主动使用。
类实例的初始化
针对源代码中的每一个类的构造方法,java编译器都产生一个<init>方法。如果类没有明确地声明任何构造方法,编译器默认产生一个无参数的构造方法,该方法仅仅调用超类的无参数构造方法。
如果构造方法通过明确地调用同一个类中的另一个构造方法开始(通过this),那么对应的<init>方法由两部分组成:
l 一个同类的<init>方法的调用
l 实现了对应构造方法的方法体的字节码(即对应的构造方法的代码)
如果构造方法不是通过一个this调用开始的,且这个对象不是Object,<init>方法则由三部分组成
l 一个超类的<init>方法的调用
l 任意实例变量初始化方法的字节马(包括定义成员变量的时候赋的初值,还有初始化块)
l 实现了对应构造方法的方法体的字节码(即对应的构造方法的代码)
在调用<init>之前,虚拟机为新的对象准备好了堆内存,并把实例变量初始化为默认初始值。
public class Test {
static String a = "string-a";
static String b;
String c = "stirng-c";
String d;
static String e = getStaticString("string-e");
static {
printStatic("before static");
b = "string-b";
printStatic("after static");
}
static String f = getStaticString("string-f");
public static String getStaticString(String s)
{
System.out.println("getStaticString(" + s + ")");
return s;
}
public String getString(String s)
{
System.out.println("getString(" + s + ")");
return s;
}
String g = getString("string-g");
{
System.out.println("before {");
g = getString("string-g-new");
System.out.println("after }");
}
String h = getString("string-h");
public static void printStatic(String title) {
System.out.println("---------" + title + "---------");
System.out.println("a = "" + a + """);
System.out.println("b = "" + b + """);
}
public Test() {
print("before constructor");
d = "string-d";
print("after constructor");
}
public void print(String title) {
System.out.println("---------" + title + "---------");
System.out.println("a = "" + a + """);
System.out.println("b = "" + b + """);
System.out.println("c = "" + c + """);
System.out.println("d = "" + d + """);
}
public static void main(String[] args) {
new Test();
TT.f();
}
}
class T
{
static void f()
{
System.out.println("static void f()");
}
static
{
System.out.println("T is inited");
}
}
class TT extends T
{
static
{
System.out.println("TT is inited");
}
}
static String a = "string-a";
static String b;
String c = "stirng-c";
String d;
static String e = getStaticString("string-e");
static {
printStatic("before static");
b = "string-b";
printStatic("after static");
}
static String f = getStaticString("string-f");
public static String getStaticString(String s)
{
System.out.println("getStaticString(" + s + ")");
return s;
}
public String getString(String s)
{
System.out.println("getString(" + s + ")");
return s;
}
String g = getString("string-g");
{
System.out.println("before {");
g = getString("string-g-new");
System.out.println("after }");
}
String h = getString("string-h");
public static void printStatic(String title) {
System.out.println("---------" + title + "---------");
System.out.println("a = "" + a + """);
System.out.println("b = "" + b + """);
}
public Test() {
print("before constructor");
d = "string-d";
print("after constructor");
}
public void print(String title) {
System.out.println("---------" + title + "---------");
System.out.println("a = "" + a + """);
System.out.println("b = "" + b + """);
System.out.println("c = "" + c + """);
System.out.println("d = "" + d + """);
}
public static void main(String[] args) {
new Test();
TT.f();
}
}
class T
{
static void f()
{
System.out.println("static void f()");
}
static
{
System.out.println("T is inited");
}
}
class TT extends T
{
static
{
System.out.println("TT is inited");
}
}