类进行"初始化"的必须情况(有且仅有五种情况)
1.遇到new,getstatic,putstatic或invokestatic这4条字节码指令时.
分别对应常见的4种场景,new关键字实例化对象,读取或设置类的静态字段(不包括被final修饰的字段,已在编译期把结果放入常量池中),调用类静态方法时。
public class Main {
public static void main(String[] args) {
}
static class Test{
static {
System.out.println("Init Test");
}
static int x = 3;
final static int y = 4;
static void print() {
System.out.println("has inited?");
}
}
在main函数中分别置于以下语句,观察是否执行static代码段。
new Test(); //触发初始化
System.out.println(Test.x); //触发初始化
Test.x = 4; //触发初始化
Test.print(); //触发初始化
System.out.println(Test.y); //不触发初始化
- 利用反射对类进行调用时。
在main函数中置于下面语句时,观察是否执行static代码段。
try {
Test.class.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
for (Field field : Test.class.getDeclaredFields()) {
if (field.getName().equals("x")) {
try {
System.out.println(field.get(Test.class));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
for (Field field : Test.class.getDeclaredFields()) {
if (field.getName().equals("y")) {
try {
System.out.println(field.get(Test.class));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
不管是实例化,还是访问static变量,或者是访问static final变量,都会触发初始化。但仅仅是访问field时,置于以下语句时,不会触发初始化。
for (Field field : Test.class.getDeclaredFields()){
System.out.println(field.getName());
}
- 初始化一个类时,若父类未初始化,则先初始化父类.
public class Main {
public static void main(String[] args) {
}
static class Fa {
static {
System.out.println("Init Fa");
}
static int fax = 3;
static final int fay = 4;
}
static class Test extends Fa{
static {
System.out.println("Init Test");
}
static int x = 3;
final static int y = 4;
static void print() {
System.out.println("has inited?");
}
}
}
在main函数置于以下语句
System.out.println(Test.x); //初始化父类,然后初始化子类
System.out.println(Test.fax); //初始化父类,不初始化子类
System.out.println(Test.fay); //不初始化父类,也不初始化子类
- 虚拟机启动时,主类(包含main方法的那个类),先初始化此类。
public class Main {
static {
System.out.println("Init Main");
}
public static void main(String[] args) {
try {
Test.class.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
static class Fa {
static {
System.out.println("Init Fa");
}
static int fax = 3;
static final int fay = 4;
}
static class Test extends Fa{
static {
System.out.println("Init Test");
}
static int x = 3;
final static int y = 4;
static void print() {
System.out.println("has inited?");
}
}
}
/*
打印结果:
Init Main
Init Fa
Init Test
*/
- jdk1.7 通过方法句柄的方式动态执行方法或者修改访问static变量时。
public class Main {
static {
System.out.println("Init Main");
}
public static void main(String[] args) {
MethodHandles.Lookup lookup = MethodHandles.lookup();
try {
MethodHandle methodHandle = lookup.findStatic(Test.class, "print", MethodType.methodType(void.class));
methodHandle.invoke();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}
static class Fa {
static {
System.out.println("Init Fa");
}
static int fax = 3;
static final int fay = 4;
}
static class Test extends Fa{
static {
System.out.println("Init Test");
}
static int x = 3;
final static int y = 4;
static void print() {
System.out.println("has inited?");
}
}
}
网友评论