案列分析代码如下:(有需求的可以复制运行一下Java代码)
class Father
{
Father() {//父类的无参构造方法
show();
}
void show() {
System.out.println("父类的show方法");
}
{
System.out.println("这是父类代码块");
}
static {
System.out.println("这是父类静态代码块");
}
}
class Son extends Father
{
int num = 9;//非static变量
{
System.out.println("这是子类的代码块------"+num);
num = 10;
}
Son() {//子类无参构造方法
//此处有隐藏的 super();
System.out.println("这是子类的无参构造方法------"+num);
}
static {
System.out.println("这是子类静态代码块");
}
void show() {
System.out.println("子类的show方法-------" + num);
}
}
public class demo{
public static void main(String[] args){
new Son();
}
}
运行结果
1本案例分析
new Son(); ==> 找到Son类,到Son()构造方法,首行有隐藏的super();即发现继承了 Father类 ==> 找到Father类,发现Father没有继承其他类,就会默认继承Object类,然后为Object类静态属性分配空间并赋于初值 ==> 回到Father类,执行了Father类的静态代码块,大家会发现,我把Father类的静态代码块写在其他语句下面,还是先执行了它。
static {
System.out.println("这是父类静态代码块");
}
接着又回到Son类,执行Son类的静态代码块
static {
System.out.println("这是子类静态代码块");
}
又回到Father类执行Father类的代码块
{
System.out.println("这是父类代码块");
}
再执行Father类的构造方法,由于此时构造方法调用了show()方法,而Son类又重写了show()方法,所以会找到Son类的show()方法执行,为什么执行结果是 “子类的show方法-------0”?变量num的值为什么是0,这个我也不知道,希望有大神可以指教一下我。为什么Father类的show()方法没有打印?是因为没有调用它,如果Son类没有重写show()方法,就会执行Father类的show()方法了。
Father() { //父类的无参构造方法
show();
}
接着继续执行Son类中的非静态属性和代码块
int num = 9;//非static变量
{
System.out.println("这是子类的代码块------"+num);
num = 10;
}
再执行Son类中的构造方法
Son() { //子类无参构造方法
//此处有隐藏的 super();
System.out.println("这是子类的无参构造方法------"+num);
}
总结,new一个对象时代码的执行顺序
(1)加载父类(以下序号相同,表明初始化是按代码从上到下的顺序来的)
1.为父类的静态属性分配空间并赋于初值
1.执行父类静态初始化块;
(2)加载子类
2.为子类的静态属性分配空间并赋于初值
2.执行子类的静态的内容;
(3)加载父类构造器
3.初始化父类的非静态属性并赋于初值
3.执行父类的非静态代码块;
4.执行父类的构造方法;
(4)加载子类构造器
5.初始化子类的非静态属性并赋于初值
5.执行子类的非静态代码块;
6.执行子类的构造方法.
总之一句话,静态代码块内容先执行(先父后子),接着执行父类非静态代码块和构造方法,然后执行子类非静态代码块和构造方法。(先父后子)
当然细分加载过程的话,看下面JVM加载过程,静态代码块是在类加载时执行,非静态代码块和加载器在实例初始化时执行。
注意两个问题:
1)静态变量和静态代码块的初始化顺序:谁在前面先初始化谁(这个也比较容易理解,初始化的时候,不可能跳着去初始化吧,比如说静态代码块在静态变量的前面,不可能先跳过静态代码块的初始化先去执行静态变量的初始化吧。)
2)子类的构造方法,不管这个构造方法带不带参数,默认的它都会先去寻找父类的不带参数的构造方法。如果父类没有不带参数的构造方法,那么子类必须用supper关键子来调用父类带参数的构造方法,否则编译不能通过。