zoukankan      html  css  js  c++  java
  • 关于静态块、静态属性、构造块、构造方法的执行顺序

    下面是在网上找到的比较典型的例子,以此来说明

    例一:

    class A {
        static {
            System.out.println("A的静态块");
        }
        private static String staticStr = getStaticStr();
        private String str = getStr();
    
        {
            System.out.println("A的实例块");
        }
        
        public A() {
            System.out.println("A的构造方法");
        }
    
        private static String getStaticStr() {
            System.out.println("A的静态属性初始化");
            return null;
        }
        private String getStr() {
            System.out.println("A的实例属性初始化");
            return null;
        }
        public static void main(String[] args) {
            new B();
            new B();
        }
    
    }
    
    class B extends A{
        private static String staticStr = getStaticStr();
        static {
            System.out.println("B的静态块");
        }
        {
            System.out.println("B的实例块");
        }
        public B() {
            System.out.println("B的构造方法");
        }
       private String str = getStr();
    private static String getStaticStr() { System.out.println("B的静态属性初始化"); return null; } private String getStr() { System.out.println("B的实例属性初始化"); return null; } }

    该段代码的执行结果为:

    A的静态块
    A的静态属性初始化
    B的静态属性初始化
    B的静态块
    A的实例属性初始化
    A的实例块
    A的构造方法
    B的实例块
    B的实例属性初始化
    B的构造方法
    A的实例属性初始化
    A的实例块
    A的构造方法
    B的实例块
    B的实例属性初始化
    B的构造方法

    由此可见,实例化子类的时候,若此类未被加载过,首先加载是父类的类对象,然后加载子类的类对象,接着实例化父类,最后实例化子类,若此类被加载过,不再加载父类和子类的类对象。

    接下来是加载顺序,当加载类对象时,首先初始化静态属性,然后执行静态块;当实例化对象时,首先执行构造块(直接写在类中的代码块),然后执行构造方法。至于各静态块和静态属性初始化哪个些执行,是按代码的先后顺序。属性、构造块(也就是上面的实例块)、构造方法之间的执行顺序(但构造块一定会在构造方法前执行),也是按代码的先后顺序。


    例二:

    public class EXA {
        private static EXA a = new EXA();  
        static {  
            System.out.println("父类--静态代码块");  
        }  
      
        public EXA() {  
            System.out.println("父类--构造函数");  
        }  
      
        {  
            System.out.println("父类--非静态代码块");  
        }  
      
        public static void main(String[] args) {
            new EXC();
            new EXC();
        }
    }
    
    class EXC extends EXA {  
        private static EXC b = new EXC();  
        static {  
            System.out.println("子类--静态代码块");  
        }  
        {  
            System.out.println("子类--非静态代码块");  
        }  
      
        public EXC() {  
            System.out.println("子类--构造函数");  
        }
    }

    该段代码的执行结果为:

    父类--非静态代码块
    父类--构造函数
    父类--静态代码块
    父类--非静态代码块
    父类--构造函数
    子类--非静态代码块
    子类--构造函数
    子类--静态代码块
    父类--非静态代码块
    父类--构造函数
    子类--非静态代码块
    子类--构造函数
    父类--非静态代码块
    父类--构造函数
    子类--非静态代码块
    子类--构造函数

    分析(非静态代码块即构造块):

    首先要加载父类EXA,由于A的静态属性在静态块的前面,先初始化静态属性(new EXA())(父类--非静态代码块;父类--构造函数),然后是静态块(父类--静态代码块);

    加载子类EXC,由于EXC的静态属性也在静态块的前面,先初始化静态属性(new EXC()),实例化子类对象的时候会先实例化父类,所以执行的顺序为(父类--非静态代码块;父类--构造函数;子类--非静态代码块;子类--构造函数),然后是静态块(子类--静态代码块)

    实例化父类EXA对象:父类--非静态代码块;父类--构造函数;

    实例化子类EXC对象:子类--非静态代码块;子类--构造函数;

    第二个new EXC():因为父类和子类都已加载,只需依次实例化父类对象和子类对象(父类--非静态代码块;父类--构造函数;子类--非静态代码块;子类--构造函数;)

    推测:若将EXA的静态块和静态属性的初始化换位置,执行结果应该为:

    父类--静态代码块
    父类--非静态代码块
    父类--构造函数
    父类--非静态代码块
    父类--构造函数
    子类--非静态代码块
    子类--构造函数
    子类--静态代码块
    父类--非静态代码块
    父类--构造函数
    子类--非静态代码块
    子类--构造函数
    父类--非静态代码块
    父类--构造函数
    子类--非静态代码块
    子类--构造函数

    public class EXA {
          
        static {  
            System.out.println("父类--静态代码块");  
        } 
        private static EXA a = new EXA();
      
        public EXA() {  
            System.out.println("父类--构造函数");  
        }  
      
        {  
            System.out.println("父类--非静态代码块");  
        }  
      
        public static void main(String[] args) {
            new EXC();
            new EXC();
        }
    }
    
    class EXC extends EXA {  
        private static EXC b = new EXC();  
        static {  
            System.out.println("子类--静态代码块");  
        }  
        {  
            System.out.println("子类--非静态代码块");  
        }  
      
        public EXC() {  
            System.out.println("子类--构造函数");  
        }
    }

    运行发现,结果证实这样。

  • 相关阅读:
    SAP dpmon
    SLD Connection Parameters for a Central SLD
    SDN有中文版论坛了
    XI Service Users
    甘特图终极版本 绝对B/S的甘特图经典
    xml文件net操纵类(c#)
    将js文件编译成动态链接库(dll)文件
    文件创建及读取的方法
    只能在执行 Render() 的过程中调用 RegisterForEventValidation(RegisterForEventValidation can only be called during Render()
    ASP.net AJAX置于框架中出现回调
  • 原文地址:https://www.cnblogs.com/maowh/p/3729971.html
Copyright © 2011-2022 走看看