代码如下
class Father {
private Integer a = 10; // 为了便于展示初始化的过程
Father() {
System.out.println(this instanceof Son);
System.out.println(((Son)this).a);
System.out.println(this.getClass().getName());
}
public static void main(String[] args) {
Father s = new Son();
System.out.println(s.a);
}
}
class Son extends Father {
public Integer a = 100;
public Son() {
//显示调用super() 写不写都一样
super();
}
}
输出的结果为:
true
null
10
然后我们修改上面的代码,其实就改动了一行
class Father {
private int a = 10;
Father() {
System.out.println(this instanceof Son);
System.out.println(this.a); //这行代码改动了
System.out.println(this.getClass().getName());
}
public static void main(String[] args) {
Father s = new Son();
System.out.println(s.a);
}
}
class Son extends Father {
public int a = 100;
public Son() {
//显示调用super() 写不写都一样
super();
}
}
输出结果为:
true
10
10
出现上面这种情况的原因是因为静态绑定和动态绑定,顺便扯上了父子类构造方法的顺序,先引入Java绑定的概念
对Java来说,绑定分为静态绑定和动态绑定;或者叫做前期绑定和后期绑定。
静态绑定
在程序执行前方法已经被绑定,针对java简单的可以理解为程序编译期的绑定;
java当中的方法只有final,static,private和构造方法以及变量使用静态绑定动态绑定
在运行时根据具体对象的类型进行绑定。提供了一些机制,可在运行期间判断对象的类型,并分别调用适当的方法。也就是说,编译器此时依然不知道对象的类型,但方法调用机制能自己去调查,找到正确的方法主体。
这个时候就可以解释上面的情况了,第一种情况是把this强转成了Son,此时Son中的a还没进行初始化,使用的是默认值null。
第二种情况因为变量是静态绑定的,所以都是10。所以在父类中,this.(变量名)输出的只能是父类中的变量,强转成子类输出,就回得到null值