【JAVA中的那些事】
那天我在进行代码测试,debug操作,看到如下情况:
发现在执行类ParentBean的static代码块的时候,出现了:ParentBean.
那疑问来了:
带着疑问我进行了疯狂google(技术的路上万事都是问自己,自己不懂问google,哈哈)
在oracle的官网有这么一段文献:
At the level of the Java Virtual Machine, every constructor written in the Java programming language (JLS §8.8) appears as an instance initialization method that has the special name . This name is supplied by a compiler. Because the name is not a valid identifier, it cannot be used directly in a program written in the Java programming language. Instance initialization methods may be invoked only within the Java Virtual Machine by the invokespecial instruction (§invokespecial), and they may be invoked only on uninitialized class instances. An instance initialization method takes on the access permissions (JLS §6.6) of the constructor from which it was derived.
A class or interface has at most one class or interface initialization method and is initialized (§5.5) by invoking that method. The initialization method of a class or interface has the special name , takes no arguments, and is void (§4.3.3).
Other methods named in a class file are of no consequence. They are not class or interface initialization methods. They cannot be invoked by any Java Virtual Machine instruction and are never invoked by the Java Virtual Machine itself.
In a class file whose version number is 51.0 or above, the method must additionally have its ACC_STATIC flag (§4.6) set in order to be the class or interface initialization method.
This requirement is new in Java SE 7. In a class file whose version number is 50.0 or below, a method named that is void and takes no arguments is considered the class or interface initialization method regardless of the setting of its ACC_STATIC flag.
The name is supplied by a compiler. Because the name is not a valid identifier, it cannot be used directly in a program written in the Java programming language. Class and interface initialization methods are invoked implicitly by the Java Virtual Machine; they are never invoked directly from any Java Virtual Machine instruction, but are invoked only indirectly as part of the class initialization process.
A method is signature polymorphic if and only if all of the following conditions hold :
It is declared in the java.lang.invoke.MethodHandle class.
It has a single formal parameter of type Object[].
It has a return type of Object.
It has the ACC_VARARGS and ACC_NATIVE flags set.
In Java SE 7, the only signature polymorphic methods are the invoke and invokeExact methods of the class java.lang.invoke.MethodHandle.
The Java Virtual Machine gives special treatment to signature polymorphic methods in the invokevirtual instruction (§invokevirtual), in order to effect invocation of a method handle. A method handle is a typed, directly executable reference to an underlying method, constructor, field, or similar low-level operation (§5.4.3.5), with optional transformations of arguments or return values. These transformations are quite general, and include such patterns as conversion, insertion, deletion, and substitution. See the java.lang.invoke package in the Java SE platform API for more information.
从以上文献可以看出来几点:
用代码形象的表示:
class X {
static Log log = LogFactory.getLog(); //
private int x = 1; //
X(){
//
}
static {
//
}
}
父类ParentBean.java
package com.zfy.core.test;
public class ParentBean {
public static int i = 1;
static {
System.out.println("ParentBean:static代码块执行");
}
public static int j = 2;
/**
* 构造器
*/
public ParentBean() {
System.out.println("ParentBean:构造器执行");
}
}
子类ChildBean.java
package com.zfy.core.test;
public class ChildBean extends ParentBean{
static {
System.out.println("ChildBean:static代码块执行");
}
/**
* 构造器
*/
public ChildBean() {
System.out.println("ChildBean:构造器执行");
}
}
其中Bean的初始化配置:
@Bean
@Lazy(true)
public ParentBean parent() {
return new ParentBean();
}
@Bean
public ChildBean child() {
return new ChildBean();
}
DEBUG一下:
F6下一步:
F6下一步:
通过上面三步的debug,你会发现static变量赋值和静态代码块都会被编译器收集在
如果再F6下一步,则会依次进入到ChildBean的static块、ParentBean的构造器、ChildBean的构造器
控制台输出:
ParentBean:static代码块执行
ChildBean:static代码块执行
ParentBean:构造器执行
ChildBean:构造器执行
从debug的结果和控制台的输出可以得出:
参考资料:
https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-2.html
https://stackoverflow.com/questions/8517121/java-what-is-the-difference-between-init-and-clinit/8517163