关于java类中代码的执行顺序

关于类中代码执行顺序

一、首先声明

  1. 静态内容包括静态代码块和静态变量,它们的执行顺序处在同一级别,谁写在前面谁先执行。
  2. 实例内容包括实例代码块1和实例变量(不包括构造方法),它们的执行顺序处在同一级别,谁写在前面谁先执行。

二、结论

执行顺序为:

  1. 父类静态内容
  2. 子类静态内容
  3. 父类实例内容
  4. 父类构造函数
  5. 子类实例内容
  6. 子类构造方法
注意:只有存在创建对象,构造方法和实例代码块才会执行,如果只是将类加载进内存,那么只会执行静态内容。

例如JDBC中,我们在注册驱动时,经常使用的一句代码:

		Class.forName("com.mysql.jdbc.Driver");

这句代码,就只是将com.mysql.jdbc.Driver加载进了内存,因为com.mysql.jdbc.Driver中有一段静态代码块:

  	  static {
  	        try {
  	            DriverManager.registerDriver(new Driver());
  	        } catch (SQLException var1) {
  	            throw new RuntimeException("Can't register driver!");
  	        }
  	    }

利用类加载进内存的时候,静态代码块会被执行的特点,就注册了驱动。

三、代码测试

1.代码

class Father
{
    static
    {
        System.out.println("父类的静态代码块执行");
    }

    public static int i = getStaticInt();

    //用于实例化静态变量,因为如果直接赋值,不能直接看到它是何时执行的
    public static int getStaticInt()
    {
        System.out.println("父类的静态变量被初始化");
        return 0;
    }

    public int j = getInstanceInt();

    public int getInstanceInt()//用于实例化实例变量
    {
        System.out.println("父类的实例变量被初始化");
        return 0;
    }

    {
        System.out.println("父类的实例代码块执行");
    }

    public Father()
    {
        System.out.println("父类的无参构造方法执行");
    }

}

class Child extends Father
{
    public static int i = getStaticInt();

    static
    {
        System.out.println("子类的静态代码块执行");
    }

    public static int getStaticInt()//用于实例化静态变量
    {
        System.out.println("子类的静态变量被初始化");
        return 0;
    }

    {
        System.out.println("子类的实例代码块执行");
    }

    public int j = getInstanceIntChild();

    public int getInstanceIntChild()//用于实例化实例变量
    {
        System.out.println("子类的实例变量被初始化");
        return 0;
    }

    public Child()
    {
        System.out.println("子类的无参构造方法执行");
    }

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

2. 执行结果

  1. 如果将main方法中的创建对象注释,结果为
    父类的静态代码块执行
    父类的静态变量被初始化
    子类的静态变量被初始化
    子类的静态代码块执行
  2. 如果放开main方法中创建对象那一行,结果为
    父类的静态代码块执行
    父类的静态变量被初始化
    子类的静态变量被初始化
    子类的静态代码块执行
    父类的实例变量被初始化
    父类的实例代码块执行
    父类的无参构造方法执行
    子类的实例代码块执行
    子类的实例变量被初始化
    子类的无参构造方法执行

3.结果分析

  1. 和上面给出的结论是一样的
  2. 为了佐证静态代码块和静态变量、实例代码块和实例变量的执行顺序是同一级别的,我特意将它们的顺序调换了,执行结果和理论结果一样
  3. 与本结论无关的东西,但我想提一嘴。父类实初始化实例变量的方法和子类初始化实例变量的方法名字我故意起得不一样,如果一样,会发生覆盖重写,而且父类中初始化它自己的实例变量时,不会调用自己中的方法,而是会去调用子类中重写之后的方法,那样的话,上面2结果中第五行“父类实例变量被初始化”会变成“子类实例变量被初始化”。静态方法可以被继承,但是不能被重写,所以实例化静态变量的方法名字我起的一样也没什么关系。

4. 最终结论

如果靠死记硬背,恐怕要花点力气。所以边理解边总结,结论为:静态先于实例,父类先于子类。实例先于构造,平级就按顺序。越前面的话,权重越大。
看我给你解释,把它们看成为一群小朋友,要给它们排队:

  1. 第一步:第一句话权重最大,所以静态的内容全部跑到最前面来,包括父类静的态变量和父类的静态代码块、子类的静态变量和子类的静态代码块,然后结合父类先于子类、平级就按顺序,就可以为所有的静态内容排好序。
  2. 第二步:第二句话权重第二,因为前面所有的静态内容已经排了,所以父类中只剩下非静态内容,包括父类的实例变量、实例代码块、构造方法,全部跑到静态内容的后面。然后结合实例先于构造、平级就按顺序,就可以为所有父类非静态内容排好序。
  3. 第三步:剩下的内容就只有子类的非静态内容,包括子类的实例变量、实例代码块、构造方法。参照第二步,即可排好。然后所有的内容就都排好了。

有不对或不懂的地方,可以指出一起讨论交流


  1. 实例代码块也称非静态代码块,只不过实例代码块听起来更好理解 ↩︎

猜你喜欢

转载自blog.csdn.net/ql_7256/article/details/106966462