继承中对方法和变量的处理不一样,大体上有两种途径来验证,一种是本文所提到的,向上转型和直接创建一个子类赋给父类型;另一种,就是在子类调用父类的构造函数,这种情况比较隐蔽,还要结合类的初始化过程就比较好理解一些。
/**
*子类赋给父类时,所得对象调用方法时,调用的是子类的方法,而引用变量时,用的却是*父类的变量
*
**/
public class TestBaseAndSubclass{
public static void main(String args[]){
SubClass sb=new SubClass();
Base bs=sb;//①向上转型
System.out.println(bs.i);//②输出的是Base中的i,1;
bs.display(); // ③ Error! 语句②输出的是父类Base中的变量i,而通过上转型的Base类型的子类对象不能调用子类的方法!而很奇怪,是不是说通过上转型sb就变成了Base类型了?所以,找不到子类方法?
}
}
class Base{
int i;
Base(){i=1;}}
}
class SubClass extends Base{
int i;
SubClass(){i=10;}
void display(){
i=10;
System.out.println("这是子类中的方法"); // ④
}
}
结论:当编译时类型与运行时类型不一样时,用父类声明对象调用方法是子类中的方法,引用的变量是子类中的变量。
1、 出现句三的原因是:用父类Base声明的对象能调用子类方法的前提是父类中定义了这个方法(因为在类型转换中,编译类型是声明类型(这里是Base),而运行类型则是对象的类型(这里是SubClase),如果Base类型中没有display()方法,那么编译不通过),所以如果在Base类中加上以下语句,那就不会出错了,并且语句③调用的是子类中的方法
void display(){
System.out.println("这是父类中的方法");
}
2、 不论是如何赋值,例如如果在语句③中插入以下两句Base bs2 = new SubClass(); bs2.display();System.out.println(bs2.i) 。调用的display()仍然是子类中的display(),引用的变量仍然是父类的变量i。