类的初始化变量和方法的执行顺序(父子类)
static和没有static的区别:
*static的属性/方法在类加载时就已经做好准备,因此类名.就可以调用,与对象存在不存在无关。
*非static的属性/方法隶属于对象,必须先创建对象,才能使用。
static的方法中,不能使用非静态的属性或者方法,必须先创建对象,然后用对象.调用;而非static的方法中,可以直接使用静态的属性或方法。
只有隶属于类(所有对象共享)的属性才能加static,static不能随便加。
代码块 -- java允许直接用{}写代码,叫代码块。
*写在类体中的代码块叫构造块,每创建一个对象,构造块都会被执行一次。
*前面加static的构造块叫静态代码块,类加载时执行一次。
对象创建的过程
a.单个对象创建的执行过程
(1)main()方法是程序的入口,使用new关键字创建对象时会在堆区申请内存空间;
(2)若成员变量没有指定初始值,则采用默认初始化方式处理;
(3)若成员变量进行显式初始化,则采用指定的初始值进行处理;
(4)执行构造块中的代码,可以对成员变量进行赋值操作;
(5)执行构造方法体中的代码,可以对成员变量进行再次赋值;
(6)此时对象创建完毕,继续向下执行;
b.子类对象创建的执行过程
(1)main()方法是程序的入口,使用new关键字创建对象时会在堆区申请内存空间;
(2)先加载父类再加载子类,因此先执行父类的静态代码块再执行子类的静态代码块;
(3)执行父类的构造块和父类的构造方法体,此时内部的父类对象构造完毕;
(4)执行子类的构造块和子类的构造方法体,此时子类对象构造完毕;
(5)构造完毕后继续向下执行;
执行顺序:(静态代码块和静态变量谁在前面就先执行谁)
父类静态代变量、
父类静态代码块、
子类静态变量、
子类静态代码块、
父类非静态变量(父类实例成员变量)、
父类构造函数、
子类非静态变量(子类实例成员变量)、
子类构造函数。
代码示例:
package com.jdk.learn; public class ClassLoaderTest { public static void main(String[] args) { son sons=new son(); } } class parent{ private static int a=1; private static int b; private int c=initc(); static { b=1; System.out.println("1.父类静态代码块:赋值b成功"); System.out.println("1.父类静态代码块:a的值"+a); } int initc(){ System.out.println("3.父类成员变量赋值:---> c的值"+c); this.c=12; System.out.println("3.父类成员变量赋值:---> c的值"+c); return c; } public parent(){ System.out.println("4.父类构造方式开始执行---> a:"+a+",b:"+b); System.out.println("4.父类构造方式开始执行---> c:"+c); } } class son extends parent{ private static int sa=1; private static int sb; private int sc=initc2(); static { sb=1; System.out.println("2.子类静态代码块:赋值sb成功"); System.out.println("2.子类静态代码块:sa的值"+sa); } int initc2(){ System.out.println("5.子类成员变量赋值--->:sc的值"+sc); this.sc=12; return sc; } public son(){ System.out.println("6.子类构造方式开始执行---> sa:"+sa+",sb:"+sb); System.out.println("6.子类构造方式开始执行---> sc:"+sc); } }
执行结果:
1.父类静态代码块:赋值b成功 1.父类静态代码块:a的值1 2.子类静态代码块:赋值sb成功 2.子类静态代码块:sa的值1 3.父类成员变量赋值:---> c的值0 3.父类成员变量赋值:---> c的值12 4.父类构造方式开始执行---> a:1,b:1 4.父类构造方式开始执行---> c:12 5.子类成员变量赋值--->:sc的值0 6.子类构造方式开始执行---> sa:1,sb:1 6.子类构造方式开始执行---> sc:12
总结:
当我们进行new实例化进行操作的时候,JVM都进行了什么操作呢?
如果你看过深入理解jvm的话,应该会比较清楚,当我们使用new关键字进行实例化的时候,会进行如下几步处理:
加载
此阶段加载类的字节码信息到内存
连接
此阶段进行验证,分配默认值,符号引用转直接引用
初始化
为成员进行赋值等
使用
对实例进行操作比如sons.toString()
对于我们的实例而言,我们只关注连接和初始化阶段即可。
连接阶段我们按照类结构(成员变量(先),方法(后)等)的顺序(不是书写顺序),先对变量进行赋默认值0,对象的话为null。
初始化的时候,就是对对象进行赋值,比如c执行initc()进行赋值。
参考博客:https://blog.csdn.net/u014042066/article/details/77574956