其实是想写篇关于类的加载顺序的文章的,可是编程举几个例子证明加载顺序的时候却有了意外收获...
先上代码:
Parent类:
public class Parent {
public Parent() {
System.out.println("这是父类的构造方法");
}
public void d_Parent() {
System.out.println("这是父类的非静态方法");
}
public static void s_Parent() {
System.out.println("这是父类的静态方法");
}
static{
System.out.println("这是父类的静态代码快");
}
{
System.out.println("这是父类的构造代码快");
}
}
Child类:
public class Child extends Parent{
public Child() {
System.out.println("这是子类的构造方法");
}
public static void s_Child() {
System.out.println("这是子类的静态方法");
}
public void d_Child() {
System.out.println("这是子类的非静态方法");
}
static{
System.out.println("这是子类的静态代码快");
}
{
System.out.println("这是子类的构造代码快");
}
public static void main(String[] args) {
System.out.println("before new Child()");
new Child();
}
}
看看输出结果:
这是父类的静态代码快
这是子类的静态代码快
before new Child()
这是父类的构造代码快
这是父类的构造方法
这是子类的构造代码快
这是子类的构造方法
输出结果神奇吧,简单分析一下:当JVM加载类的时候,是将类文件中的一行行内容全部加载到内存中(除了实例变量,因为这是对象私有的),但不执行任何语句,即使在加载时期有输出语句也不执行。加载的时候,将静态成员变量(类变量),构造代码块,静态代码块以及静态方法加载到方法区的静态部分,非静态方法以及构造方法加载到方法区的非静态部分。
类文件加载好以后,开始执行静态代码块,然后在堆内存中开辟空间,分配内存地址。接着开始在堆内存中对实例变量进行默认初始化,然后执行构造代码块,对对象进行对应的构造代码块的初始化,最后进行构造函数的初始化,对对象进行对应的构造函数初始化。
静态代码块用于给类初始化,类加载的时候就会被执行;
构造代码块用于给对应对象初始化,只要创建对象就会被执行,而且执行的顺序优先于构造函数;
构造函数用于给对应对象初始化,只要创建对象,就会选择相应的构造函数进行初始化。
总结:静态代码块是最先执行的,然后执行父类的非静态代码块以及父类的构造方法,接着去执行子类的非静态代码块以及子类的构造方法。
即顺序为:初始化父类静态代码块->初始化子类静态代码块->初始化父类构造代码块->初始化父类构造方法->初始化子类构造代码块->初始化子类构造方法
PS
根据输出结果,"before new Child()"是在是在执行完静态代码块以后然后才输出的,这就证明静态代码块是不需要创建对象就可以执行的,只要类加载完就可以执行,而构造代码块以及构造方法是在执行创建对象的时候才进行初始化的。
那么,什么时候才会加载类呢?
1.执行new Child() 操作的时候;
2.使用类中的静态成员变量或者静态方法的时候;
3.在命令行中执行:java Child的时候。
刚刚在百度搜索静态代码块的时候又发现了点新的知识,我就懒得改前面写的文章了,直接加载后面了。Parent类不变,变的是Child类,在Child类里new两次匿名的Child对象,代码如下:
public class Child extends Parent{
public Child() {
System.out.println("这是子类的构造方法");
}
public static void s_Child() {
System.out.println("这是子类的静态方法");
}
public void d_Child() {
System.out.println("这是子类的非静态方法");
}
static{
System.out.println("这是子类的静态代码快");
}
{
System.out.println("这是子类的构造代码快");
}
public static void main(String[] args) {
System.out.println("before new Child()");
new Child();
new Child();
}
}
输出结果:
这是父类的静态代码快
这是子类的静态代码快
before new Child()
这是父类的构造代码快
这是父类的构造方法
这是子类的构造代码快
这是子类的构造方法
这是父类的构造代码快
这是父类的构造方法
这是子类的构造代码快
这是子类的构造方法
分析:当我们New两次对象的时候,父类和子类的静态代码块只输出了一次,原因其实很简单:
静态代码块是属于整个类的,而不属于对象的。当类在加载以后就执行了静态代码块,然后才去执行new一个新的对象的操作。而且静态代码块只在类加载的时候执行一次,而构造方法以及构造代码块是属于对象的,new一次对象就执行一次。
参考资料:
http://blog.csdn.net/hmzdbql/article/details/8097172
声明:
1.原创内容,转载请注明原文链接
2.摩罗不写博客,所有内容只是摩罗笔记,如有错误或者您有更好的意见,欢迎指正。
欢迎关注行者摩罗微信公众号(xingzhemoluo),共同交流编程经验,扫描下方二维码即可;