1 public class BaseTest { 2 3 public static void main(String[] args) 4 { 5 new Derived(); // 1 6 } 7 } 8 9 class Base 10 { 11 private int i =2; 12 13 public Base() 14 { 15 this.display(); 16 } 17 public void display() 18 { 19 System.out.println("Base i is:"+i); 20 } 21 } 22 23 class Derived extends Base 24 { 25 private int i =22; 26 public Derived() 27 { 28 i =222; 29 } 30 public void display() 31 { 32 System.out.println("Derived i is :"+i); //2 33 } 34 35 }
运行结果:
Derived i is :0
分析:new Derived();
系统会自动调用Base类中无参数的构造器来进行初始化。
构造器只是负责对Java对象实例变量执行初始化(也就是赋初始值),在执行构造器代码之前,该对象所占的内存已经被分配下来,这些内存里值都是默认值 0或者false,
或者null(引用类型的变量)。
当执行到1时,系统先为Derived对象分配内存空间,此时需要分配两块内存,用于存放Dericed对象的两个i实例变量,这两个i 一个属于Base定义的i实例变量,一个属于Derived定义的i实例变量。此时值都是0;
接下来在执行Derived类的构造器之前,先执行Base类的构造器。this.display();
这里的this代表谁?---当this在构造器中时,this代表正在初始化的java对象,此时的情况是:this位于Base()构造器中,但是这些代码实际在Derived()构造器内执行---是Derived()构造器隐式调用了Base()构造器的代码。此时 this.i 应该是2,this虽然代表Derived对象,但它却位于Base构造器中,它的编译时类型是Base,而它实际引用一个Derived对象。
当变量的编译时类型和运行时类型不同时,通过该变量访问它引用的对象的实例变量时,该实例变量的值由声明该变量的类型决定,但通过该变量调用它引用的对象的实例方法时,该方法行为将由它实际所引用的对象所决定。
因此在调用this.display()时,则实际变现出Derived对象的行为,即输出 Derived i is: 0.
程序创建一个子类对象时,系统不经会为该类中定义的实例变量分配内存,也会为其父类中定义的所有实例变量分配内存,及时子类定义了与父类中同名实例。
public class Apple extends Fruit { @Override public void info() { System.out.println("Apple方法"); } public void AccessSuperInfo() { super.info(); } public Fruit getSuper() { return super.getThis(); } String color="红色"; public static void main(String[] args) { Apple a = new Apple(); Fruit f = a.getSuper(); System.out.println("a 和f 所引用的对象是否相同"+(a==f)); System.out.println("访问a所引用的对象的color实例变量:"+a.color); System.out.println("访问f所引用的对象的color实例变量:"+f.color); a.info(); f.info(); a.AccessSuperInfo(); } } class Fruit { String color ="未确定颜色"; public Fruit getThis() { return this; } public void info() { System.out.println("Fruit方法"); } }
运行结果:
a 和f 所引用的对象是否相同true
访问a所引用的对象的color实例变量:红色
访问f所引用的对象的color实例变量:未确定颜色
Apple方法
Apple方法
Fruit方法