我们都知道 类的加载 一定是 父类构造器执行 然后是子类构造器
class Base
{
// 定义了一个名为i的实例变量
private int i = 2;
public Base()
{
this.display();
}
public void display()
{
System.out.println(i);
}
}
// 继承Base的Derived子类
class Derived extends Base
{
// 定义了一个名为i的实例变量
private int i = 22;
// 构造器,将实例变量i初始化为222
public Derived()
{
i = 222; // ②
}
public void display()
{
System.out.println(i);
}
}
public class Test
{
public static void main(String[] args)
{
// 创建Derived的构造器创建实例
new Derived(); // ①
}
}
请猜下最后打印多少呢
没猜到吧
下面 解释一下
当我们new Derived(); 时 会给这个对象分配空间,但是会为这个对象分配 2个空间 ,1个是 Base里的i ,另一个是 Derived里的i ,此时 2个变量都是0,
然后执行父类构造器 但是最终打印了0 ,这是什么鬼,明明调用了 display()这个方法 ,而且Base 的i 已经显示的赋值为2 ,结果打印了0,。
关于这个 问题关键在于 调用这个方法的this 这个关键字,this 在构造器中表示正在初始化的对象
我们在这个 Base类的构造器中加入这个代码
// 直接输出this.i System.out.println(this.i)
class Base
{
// 定义了一个名为i的实例变量
private int i = 2;
public Base()
{
// 直接输出this.i
System.out.println(this.i);
this.display();
}
public void display()
{
System.out.println(i);
}
}
// 继承Base的Derived子类
class Derived extends Base
{
// 定义了一个名为i的实例变量
private int i = 22;
// 构造器,将实例变量i初始化为222
public Derived()
{
i = 222;
}
public void display()
{
System.out.println(i);
}
}
public class Test2
{
public static void main(String[] args)
{
// 创建Derived的构造器创建实例
new Derived();
}
}
此时会输出多少呢
答案可能都没想到
对没错 就是 2,0 为什么 ? 明明这个this 代表的是 Derived对象 为什么会输出 2呢
因为 this虽然代表 Derived 对象 但是这个呢 是处于 Base构造器中,他的编译时类型 为 Base
实际指向的是 Derived 对象
我们验证一下 在 Derived类加上sub()方法
class Base
{
// 定义了一个名为i的实例变量
private int i = 2;
public Base()
{
// 直接输出this.i
System.out.println(this.i);
this.display();
// 输出this实际的类型,将看到输出Derived
System.out.println(this.getClass());
// 因为this的编译类型是Base,所以依然不能调用sub()方法,
// this.sub();
}
public void display()
{
System.out.println(i);
}
}
// 继承Base的Derived子类
class Derived extends Base
{
// 定义了一个名为i的实例变量
private int i = 22;
// 构造器,将实例变量i初始化为222
public Derived()
{
i = 222;
}
public void display()
{
System.out.println(i);
}
public void sub(){}
}
public class Test3
{
public static void main(String[] args)
{
// 创建Derived的构造器创建实例
new Derived();
}
}
从这个 this.getClass() 这个方法获取的是Derived对象,但是 我们在Base 构造器中调用sub ()方法时,出现编译不通过的问题 ,原因是这个this 在编译时类型为Base
总结
当变量的编译时类型和运行时类型不同时,访问他引用的对象实例变量时 ,是由声明该变量的对象类型决定的 比如 Base 里的 this.i , 但是访问他引用的对象实例方法时,是由变量的实际引用的对象决定的 比如 Base 构造器里调用的 this.sub() 就会在编译时报错