JVM运行之前会执行一个叫做类加载器的子系统,叫做ClassLoader,那么类里面那么多“元素”,究竟是个什么顺序呢,写几行代码测试一下,通过给每个方法和代码快和静态变量打上断点来测试:
class Person {private String name;public Person(String name) {method();this.name = name;method();}static String password = "123";static {System.out.println("静态代码快");}static String tell = "123456789";{System.out.println("普通代码快代码快");}public void method() {System.out.println(name);System.out.println("普通方法");}public static void main(String[] args) {new Person("Jay");}}// 输出结果:// 静态代码快// 普通代码快代码快// null// 普通方法// Jay// 普通方法
结果显示:
1.静态代码块/静态类变量(二者很相似,都是以static开头,只不过一个是只有一个变量,另外一个是代码快而已,他们的地位是平等的,谁写在前面就谁先执行)
=>2.非静态代码快
=>3.构造方法
=>4.在静态方法中初始化非静态成员变量
事实上,很多时候我们在构造方法里面做一些事情,我们都很喜欢直接把需要做的事情放在this.name = name之后,这样做其实是很好的,因为在赋值完毕之后其实对象就已经构造出来了,而不是等到构造方法的最后一个"}"完了之后才算构造完毕。甚至 有些时候我们如果不需要使用成员变量,把需要做到事情写在构造方法的第一行都是可以的,这个时候其实对象已经构造出来,只不过没有初始化成员变量而已,但是又一点,如果需要在子类调用父类构造方法,那就必须要把父类的构造方法写在第一行,不然编译通不过。
那么:由此我们推到子类继承父类的时候,又是什么情况呢,下面代码:
class Person {private String age;public Person() {method1();System.out.println("父类构造方法");method1();}static String Email = "123@";static {System.out.println("父类静态代码块");}static String address = "四川成都";{System.out.println("父类非静态代码块");}public void method1() {System.out.println(age);}}public class Chinese extends Person {private String name;public Chinese(String name) {method();this.name = name;method();}static String password = "123";static {System.out.println("静态代码快");}static String tell = "123456789";{System.out.println("普通代码快代码快");}public void method() {System.out.println(name);System.out.println("普通方法");}public static void main(String[] args) {new Chinese("Jay");}}// 父类静态代码块// 静态代码快// 父类非静态代码块// null// 父类构造方法// null// 普通代码快代码快// null// 普通方法// Jay// 普通方法
总结:不难看出,首先是父类静态变量/静态代码块 => 子类静态变量/静态代码块 => 父类非静态代码快 => 父类构造方法 => 子类非静态代码快 => 子类构造方法 => 其他
跟上面不谋而合,在一个类中,静态的首先执行,也就是当JVM启动之后,类加载器把静态的变量加载进去,不用执行其他方法就已经把静态的东西执行了,然后就是非静态的代码块,再之后才是构造方法,而在构造方法里面是按照顺序执行的(这是废话,同一个方法里面的代码本来就是按顺序执行的)。
说明:静态代码块和静态类变量的执行顺序可以通过打断点的方式得出上诉结论,就是谁在前面就先执行谁,二者的地位是平等的。