java初始化顺序

来源:互联网 发布:永清环保怎么样知乎 编辑:程序博客网 时间:2024/05/16 14:29


静态变量、静态语句块、成员变量、构造语句块(就是只有大括号的那块)以及构造函数的执行顺序。

对象的初始化顺序:(1)类加载之后,按从上到下(从父类到子类)执行被static修饰的变量和语句块;(2)当static语句执行完之后,再执行main方法;(3)如果有语句new了自身的对象,将从上到下(从父类到子类)执行成员变量、构造代码块、构造器(两者可以说绑定在一起)。


感谢@程序媛想事儿

class HelloC{
public HelloC() {
System.out.println("HelloC");
}
}


class HelloA {

HelloC helloC=new HelloC();


    public HelloA() {
        System.out.println("HelloA");
    }
    
    { System.out.println("I'm A class"); }
    
    static { System.out.println("static A"); }


}


public class HelloB extends HelloA {

HelloC helloC=new HelloC();


    public HelloB() {
        System.out.println("HelloB");
    }
    
    { System.out.println("I'm B class"); }
    
    static { System.out.println("static B"); }
    
    public static void main(String[] args) {


        System.out.println("-------main start-------");
        new HelloB();
        new HelloB();
        System.out.println("-------main end-------");
    }
}


static A
static B
-------main start-------

HelloC
I'm A class
HelloA
I'm B class
HelloB

HelloC
I'm A class
HelloA
I'm B class
HelloB
-------main end-------



再看下面一个例子:

2.下面是PeopleChild类的定义和构造方法,每个构造方法都输出编号。在执行new Child("mike")的时候都有哪些构造方法被顺序调用?请选择输出结果 ( )

复制代码
class People {    String name;    public People() {        System.out.print(1);    }    public People(String name) {        System.out.print(2);        this.name = name;    }}class Child extends People {    People father;    public Child(String name) {        System.out.print(3);        this.name = name;        father = new People(name + ":F");    }    public Child() {        System.out.print(4);    }    }
复制代码

A312              B 32               C 432              D 132

答案:D

解析:考察的又是父类与子类的构造函数调用次序。在Java中,子类的构造过程中必须调用其父类的构造函数,是因为有继承关系存在时,子类要把父类的内容继承下来。但如果父类有多个构造函数时,该如何选择调用呢?

第一个规则:子类的构造过程中,必须调用其父类的构造方法。一个类,如果我们不写构造方法,那么编译器会帮我们加上一个默认的构造方法(就是没有参数的构造方法),但是如果你自己写了构造方法,那么编译器就不会给你添加了,所以有时候当你new一个子类对象的时候,肯定调用了子类的构造方法,但是如果在子类构造方法中我们并没有显示的调用基类的构造方法,如:super();  这样就会调用父类没有参数的构造方法。    

第二个规则:如果子类的构造方法中既没有显示的调用基类构造方法,而基类中又没有无参的构造方法,则编译出错,所以,通常我们需要显示的:super(参数列表),来调用父类有参数的构造函数,此时无参的构造函数就不会被调用。

总之,一句话:子类没有显示调用父类构造函数,不管子类构造函数是否带参数都默认调用父类无参的构造函数,若父类没有则编译出错。


  第三个例子,多态
public class Test {      
        public static void main(String[] args) {    
            Base b = new Sub();      //向上引用时,输出的b.x是父类成员变量的值
        System.out.println(b.x);    
      }    
   }   


   class Base {  
       int x = 10;              1


       public Base() {  
            this.printMessage();   2
          x = 20;                 4
      }    


      public void printMessage() {    
       System.out.println("Base.x = " + x); 
       }    
    }     
    class Sub extends Base {  
      int x = 30;     5
        public Sub() {    
     this.printMessage();   6
        x = 40;    7
       }     


     public void printMessage() {  
           System.out.println("Sub.x = " + x);   3
      }    
   }  

运行结果为:

Sub.x = 0
Sub.x = 30
20

此时类的初始化顺序为:

(1)子类 Sub 的成员变量的默认值0、false、null;

(2)初始化父类成员变量;
  (2)调用父类构造函数;
  (3)按顺序分别调用要子类 Sub 成员变量和实例成员变量的初始化表达式;
  (4)调用本身构造函数



0 0