实例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
/**
* Created by fei on 2017/5/31.
*/
public class SonClass extends ParentClass{
public SonClass(){
System.out.println( "SonClass's constructor" );
}
{ System.out.println( "SonClass's block" );}
static {
System.out.println( "SonClass's static block " );
}
public static void main(String[] args) {
System.out.println( "------ main start ------ " );
new SonClass();
System.out.println( "------ main end ------ " );
}
}
class ParentClass{
public ParentClass(){
System.out.println( "ParentClass's constructor" );
}
{ System.out.println( "ParentClass's block" );}
static {
System.out.println( "ParentClass's static block " );
}
}
|
运行结果:
1
2
3
4
5
6
7
8
|
ParentClass's static block
SonClass's static block
------ main start ------
ParentClass's block
ParentClass's constructor
SonClass's block
SonClass's constructor
------ main end ------
|
根据运行结果,一目了然,在执行 main 方法中 new SonClass() 之前,就在类加载之后执行了类中 static 代码块。然后再进入main方法,执行new操作,当然显而易见,在执行new子类操作的时候,是要先进行其父类的构造,即先执行父类的构造代码块(代码中只用大括号包裹的那段代码)以及构造函数 ,然后再执行子类的构造代码块以及构造函数。
修改一下代码,再来看看运行的结果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
/**
* Created by fei on 2017/5/31.
*/
public class SonClass extends ParentClass{
ParentClass parentClass;
public SonClass(){
System.out.println( "1" );
}
public SonClass(String name){
System.out.println( "2" );
this .name = name;
parentClass = new ParentClass( "FEI" );
}
public static void main(String[] args) {
System.out.println( "------ main start ------ " );
new SonClass( "fei" );
System.out.println( "------ main end ------ " );
}
}
class ParentClass{
String name ;
public ParentClass(){
System.out.println( "3" );
}
public ParentClass(String name){
System.out.println( "4" );
this .name = name ;
}
}
|
运行的顺序是:
1
2
3
4
5
|
------ main start ------
3
2
4
------ main end ------
|
第一个规则:子类的构造过程中,必须调用其父类的构造方法。一个类,如果我们不写构造方法,那么编译器会帮我们加上一个默认的构造方法(就是没有参数的构造方法),但是如果你自己写了构造方法,那么编译器就不会给你添加了,所以有时候当你new一个子类对象的时候,肯定调用了子类的构造方法,但是如果在子类构造方法中我们并没有显示的调用基类的构造方法,如:super(); 这样就会调用父类没有参数的构造方法。
第二个规则:如果子类的构造方法中既没有显示的调用基类构造方法,而基类中又没有无参的构造方法,则编译出错,所以,通常我们需要显示的:super(参数列表),来调用父类有参数的构造函数,此时无参的构造函数就不会被调用。
总之,一句话:子类没有显示调用父类构造函数,不管子类构造函数是否带参数都默认调用父类无参的构造函数,若父类没有则编译出错。
还是两个类,我们再更改一下。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
/**
* Created by fei on 2017/5/31.
*/
public class SonClass extends ParentClass{
private String name = "SonClass" ;
public SonClass() {
printName();
}
public void printName() {
System.out.println( "SonClass print name: " + name);
}
public static void main(String[] args){
new SonClass();
}
}
class ParentClass{
private String name = "ParentClass" ;
public ParentClass() {
//System.out.println(this.getClass());
printName();
}
public void printName() {
System.out.println( "ParentClass print name: " + name);
}
}
|
看了上面的两个例子,最后这个例子就很容易被迷惑,可能有人会觉得运行结果是类似这样的:
1
2
|
ParentClass print name: ParentClass
SonClass print name: SonClass
|
或者是:
1
2
|
ParentClass print name: SonClass
SonClass print name: SonClass
|
但真正的结果是这样的:
1
2
|
SonClass print name: null
SonClass print name: SonClass
|
为什么会这样,其实只要打开代码中父类构造器中的这句注释,就很容易理解了:System.out.println(this.getClass())
结果是:
1
|
class SonClass
|
没错,父类中的this引用是子类实例对象,所以在父类构造函数里调用的还是子类的printName()方法。具体原因也并我能十分肯定,我个人浅见,是因为虽然我们调用了父类的构造方法,但是我们并没有实例化出父类的实例对象,所以this还是指向的是子类的引用。
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!
原文链接:http://blog.csdn.net/zhangjunfei12103323/article/details/72821071