• java初始化构造函数调用顺序


    类初始化时构造函数调用顺序:

      (1)初始化对象的存储空间为零或null值;
      (2)调用父类构造函数;
      (3)按顺序分别调用类成员变量和实例成员变量的初始化表达式;
      (4)调用本身构造函数

    例子:
    public class Dollar extends Money{
         Rmb r=new Rmb()
         public Dollar(){
          System.out.println("Dollar is construct!");
         }
         public static void main(String[] args){

          new Dollar();  

       }
    }

    class Money{
     public Money(){
      System.out.println("Money is construct");
     }
    }

    class Rmb{
     public Rmb(){
      System.out.println("RMB is construct");
     }
    }

    输出结果:
    Money is construct
    RMB is construct
    Dollar is construct!

     

    我们再自己写一个程序,以测试运行顺序:
     
     


    输出结果:

       说明此时的运行顺序为:

    1.    父类类成员变量
    2.    父类静态块
    3.    自身类成员变量
    4.    自身静态块
    5.    父类实例成员变量
    6.    父类块
    7.    父类构造器
    8.    自身实例成员变量
    9.    自身块
    10.    自身构造器 

     再来看下伯乐在线小组的一个热门讨论帖:

    携程 Java 工程师的一道面向对象面试题

    public class Base {

    private String baseName = "base";

      public Base() {

        callName();

      }

    public void callName() {

      System.out.println(baseName);

    }

    static class Sub extends Base {

      private String baseName = "sub";

      public void callName() {

        System.out.println(baseName);

      }

    }

      public static void main(String[] args) {

        Base b = new Sub();

      }

    }

    求这段程序的输出。

    未老莫还乡 的评论:

     

    【不要在构造器里调用可能被重载的虚方法,这是极度危险的】。构造器的初始化顺序大概是 父类静态块 子类静态块 父类初始化语句 父类构造函器 子类初始化语句 子类构造器。父类构造器执行的时候,调用了子类的重载方法,然而子类的类字段还在刚初始化的阶段,刚完成内存布局,只能输出null。

    ihuning 的精华评论:

    看我大师归来:

    1. Base b = new Sub();

    2. Base b = 直接忽略,从 new Sub();开始

    3. 类加载器加载 Base,Sub 类到jvm;

    4. 为Base,Sub 类中的两个属性baseName 分配存储空间,但是不初始化;

    注意:属性的初始化时放在构造器中,按照代码顺序执行的。

    5. new Sub会调用Sub的无参构造器,而在这个构造器中会隐式调用父类Base的无参构造器;

    6. 父类Base的构造器中代码本质是

    public Base()

    {

    baseName = "base";

    callName();

    }

    即父类的属性baseName 的值为base。但为何输出null,骚年别急。

    7. 因为父类构造器方法是在子类中调用的,即大环境是子类。此时,调用的方法callName()当然是指子类的方法。而这个方法打印的属性baseName当然也是子类的。那现在子类的属性baseName的值是多少呢?答案是null.因为此时子类Sub的构造器内代码本质是:

    super();

    baseName="sub";

    此时baseName="sub"还没执行。

    因此,最后的值当然是null.

     附上代码:

    public class A {
        static B b = new B(3);
        B bb = new B(4);
    
        A() {
            System.out.println("A constructor");
        }
    
        static {
            System.out.println("A static block");
        }
        {
            System.out.println("A block");
        }
    }
    public class C extends A {
        static B b = new B(1);
        B bb = new B(2);
        C() {
            System.out.println("C constructor");
        }
        static {
            System.out.println("C static block");
        }
        {
            System.out.println("C block");
        }
        public static void main(String[] args) {
            C c = new C();
        }
    }
    class B {
        B(int i) {
            System.out.println("B"+i);
        }
    }
  • 相关阅读:
    贪心算法过河问题 pojo1700
    大脑的合理使用
    给自己的忠言
    篮子水果模拟消费者生产者
    线程安全高效的单例模式
    Java提高篇——JVM加载class文件的原理机制
    递归的研究
    虚拟机分区方法
    使用spark dataSet 和rdd 解决 某个用户在某个地点待了多长时间
    获取数据集的好的方
  • 原文地址:https://www.cnblogs.com/wangsong/p/4903088.html
Copyright © 2020-2023  润新知