构造器
每个类都默认有一个无参的构造器,在使用类创建的对象时,会优先调用构造器,如果手动添加了构造器,那么默认的无参构造器将会消失
无参构造器
创建如下类
1 2 3 4 5 6 7 8 9
| public class Root { public void print() { System.out.println("Root的print方法"); }
public Root() { System.out.println("Root的构造器"); } }
|
使用如下方式调用,将会输出
构造器重载
再给Root添加一个有参数的构造器,然后在无参构造器中调用它,如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class Root { public void print() { System.out.println("Root的print方法"); }
public Root() { this("Root无参构造器调用"); System.out.println("Root的构造器"); }
public Root(String value) { System.out.println("Root的构造器,参数 = " + value); } }
|
使用如下方式调用,将会输出
这是因为在Root的无参构造器中使用this()调用了另外一个构造器,需要注意的是,使用this()对构造器的重载中,必须在构造器的第一行调用
调用父类构造器
创建一个Mid类,使他继承上面的Root类,并给它添加一个构造器
1 2 3 4 5
| public class Mid extends Root { public Mid() { System.out.println("Mid的构造器"); } }
|
使用如下方式调用,将会输出
由上可以得出,父类的构造器要比子类构造器先执行,这是因为如果没有手动使用super()调用父类构造器的话,在子类构造器执行前,会隐式调用父类的无参构造器
如果手动使用super()调用父类构造器,则必须要写在子类构造器执行体的第一行,这注定了this()和super()不会同时出现在同一个构造方法中
如下,当使用this()重载构造器时,super()就只能写在最后一个被重载的构造器的第一行
1 2 3 4 5 6 7 8 9 10 11
| public class Mid extends Root { public Mid() { this("Mid无参构造器调用"); System.out.println("Mid的构造器"); }
public Mid(String value) { super("Mid有参构造器调用"); System.out.println("Mid的构造器,参数 = " + value); } }
|
使用Mid创建对象,将会输出
上面代码中的调用顺序,Mid无参构造器 -> Mid有参构造器 -> Root有参构造器
初始化块
在Root和Mid中分别创建初始化块
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class Root { { System.out.println("Root的初始化块"); }
public Root() { this("Root无参构造器调用"); System.out.println("Root的构造器"); }
public Root(String value) { System.out.println("Root的构造器,参数 = " + value); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class Mid extends Root { { System.out.println("Mid的初始化块"); } public Mid() { this("Mid无参构造器调用"); System.out.println("Mid的构造器"); }
public Mid(String value) { System.out.println("Mid的构造器,参数 = " + value); } }
|
通过如下代码调用,将会输出
由上可以得出,该类的初始化块总是在该类的构造方法执行前、在super()执行后被执行
静态初始化块
在Root和Mid中分别创建静态初始化块
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public class Root { static { System.out.println("Root的静态初始化块"); }
{ System.out.println("Root的初始化块"); }
public Root() { this("Root无参构造器调用"); System.out.println("Root的构造器"); }
public Root(String value) { System.out.println("Root的构造器,参数 = " + value); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public class Mid extends Root { static { System.out.println("Mid的静态初始化块"); }
{ System.out.println("Mid的初始化块"); }
public Mid() { this("Mid无参构造器调用"); System.out.println("Mid的构造器"); }
public Mid(String value) { System.out.println("Mid的构造器,参数 = " + value); } }
|
通过如下代码调用,将会输出
由上可知,父类的静态初始化块先被执行,然后是子类的静态初始化块,接着是父类初始化块、父类构造器、子类初始化块、子类构造器。
这是因为静态初始化块与类相关联,而不是与对象相关联,所以当类被加载到内存中时,静态初始化块被执行。
而父类要先于子类加载到内存中,所以先执行了父类中的静态初始化块,然后是子类的静态初始化块。在创建Mid对象时,又执行了父类初始化块、父类构造器、子类初始化块、子类构造器。