java类中的变量以及方法的执行顺序

1. java程序的类初始化以及方法的执行顺序

首先应该明白java的类加载机制有关变量赋值的过程:

连接阶段的准备阶段为静态变量分配内存并设置初值;对于被final修饰的静态变量,则会直接赋常量值。

而对于一个没有父类的类,其加载过程应该为下面的顺序:

  1. 首先加载静态变量
  2. 然后加载静态代码块
  3. 然后加载实例变量
  4. 然后加载普通代码块
  5. 最后则加载构造函数
public class test{
    char num ='j';
    static final test2 staticFiled = new test2();
    test3 notStatic = new test3();

    public static void main(String[] args)
    {
        new test();
        test.staticMethod();
    }
     static
    {
         System.out.println("静态代码块");
    }

    {
        System.out.println("匿名代码块1");
    }

    {
        System.out.println("匿名代码块2");
    }

    test(){
        System.out.println(num);
        System.out.println("构造函数");
    }

    static void staticMethod()
    {
        System.out.println("静态方法");
    }
}
public class test3{
    test3(){
        System.out.println("非静态成员变量");
    }
}
public class test2{
    public test2(){
        System.out.println("静态成员变量");
    }
}
/**output:静态成员变量
静态代码块
非静态成员变量
匿名代码块1
匿名代码块2
j
构造函数
静态方法
 * /

1.1. 对于有父类的子类进行类加载的顺序

初始化的过程其实就是一个执行类构造器< clint>方法的过程,类构造器执行的特点和注意事项:

1).类构造器< clint>方法是由编译器自动收集类中所有类变量(静态非final变量)赋值动作和静态初始化块(static{……})中的语句合并产生的,编译器收集的顺序是由语句在源文件中出现的顺序决定。静态初始化块中只能访问到定义在它之前的类变量,定义在它之后的类变量,在前面的静态初始化中可以赋值,但是不能访问

2).类构造器< clint>方法与实例构造器< init>方法不同,它不需要显式地调用父类构造器方法,虚拟机会保证在调用子类构造器方法之前父类的构造器< clinit>方法已经执行完毕

3).由于父类构造器< clint>方法先与子类构造器执行,因此父类中定义的静态初始化块要先于子类的类变量赋值操作

4). 类构造器< clint>方法对于类和接口并不是必须的,如果一个类中没有静态初始化块,也没有类变量赋值操作,则编译器可以不为该类生成类构造器< clint>方法。

在深入理解java虚拟机中有上面的一段话,所以对于有父类的子类的加载顺序,应该为先加载父类,然后再加载子类。


public class test extends testFather{
    test3 notStatic = new test3();

    public static void main(String[] args)
    {
        new test();

        test.staticMethod();
    }

     static
     {
         System.out.println("静态代码块");
     }

    {
        System.out.println("匿名代码块2");
    }

    test(){
        System.out.println("构造函数");
    }


    static void staticMethod()
    {
        System.out.println("静态方法");
    }
}

public class testFather {

    test2 testaa = new test2();
    testFather(){
        System.out.println("我是test父类");
    }
}
public class test3{
    test3(){
        System.out.println("我是静态成员变量");
    }
}
public class test2{
    public test2(){
        System.out.println("我是test父类的成员变量的构造函数");
    }
    static {
        System.out.println("我是test父类的成员变量静态方法块");
    }
    {
        System.out.println("我是test父类的成员变量的代码块");

    }
}
/**
静态代码块
我是test父类的成员变量静态方法块
我是test父类的成员变量的代码块
我是test父类的成员变量的构造函数
我是test父类
我是静态成员变量
匿名代码块2
构造函数
静态方法
*/

由此可见,在导出类构造器构造前总会默认调用基类构造器(从Object类开始调用),并且父类的静态代码块以及静态变量也会先于构造器进行初始化。

posted @ 2020-03-11 13:23  Ysalng  阅读(611)  评论(0编辑  收藏  举报