请看以下“变态”的类
ParentChildTest.Java示例
public class ParentChildTest {
public static void main(String[] args) {
Parent parent=new Parent();
parent.printValue();
Child child=new Child();
child.printValue();
parent=child;
parent.printValue();
parent.myValue++;
parent.printValue();
((Child)parent).myValue++;//
parent.printValue();
}
}
class Parent{
public int myValue=100;
public void printValue() {
System.out.println("Parent.printValue(),myValue="+myValue);
}
}
class Child extends Parent{
public int myValue=200;
public void printValue() {
System.out.println("Child.printValue(),myValue="+myValue);
}
}
1. 程序运行结果是什么? 2. 你如何解释会得到这样的输出? 3. 计算机是不会出错的,之所以得到这样的运行结果也是有原因的,那么从这些运行结果中,你能总结出Java的哪些语法特性?
程序运行结果:
解释:
父类对象被定义成子类类型(家族的具体化)
既然子类继承父类,所以子类更能代表这一个家族的具体表现,一个父类的对象被定义成子类类型时就具有了父类的属性和方法。
反过来子类对象不能被定义成父类类型
子类对象为什么不能被定义成父类类型呢?因为子类继承于父类,因此子类拥有的方法很可能比父类多,因为除了继承自父类的全部属性和方法外,子类有可能定义了其他的方法,所以大体上看子类的量级要比父类大,所以父类对象可以定义成子类对象,因为多出来的方法可以直接使用子类的,而反过来的话就不行了,因为子类对象不知道如何砍掉那些多出来的方法。
所以,一句话就是小盒子(父类对象)可以套进大盒子(子类)里,大盒子(子类对象)不能套进小盒子(父类)里。
同理,父类对象可以被子类对象赋值(被定义成子类类型),子类对象不能被父类对象赋值。
父类对象只有当明确转换为子类对象时才可以直接控制对象中的属性,只是通过赋值来使父类对象变成子类类型的办法不能使父类对象完全控制对象中的属性。
如果子类与父类有相同的字段,则子类中的字段会代替或隐藏父类的字段,子类方法中访问的是子类中的字段(而不是父类中的字段)。
换言之,一旦子类父类具有相同名称的字段,就会使继承的情况变得复杂,子类中的父类同名变量或方法就会褪色而不易被调用。
比如,父类子类都有名为F的属性或方法,那么在继承时,子类就会有两个F属性或方法,一个继承于父类(由父类定义),而另一个由子类自己定义。生成一个子类对象时,子类对象一旦调用F属性或执行F方法就会优先使用子类自己的F属性或执行子类自己的F方法,如果要强行使用父类的F属性或执行父类F方法,得在子类定义中使用super.F()来调用。
总结:(1)当子类与父类拥有一样的方法,并且让一个父类变量引用一个子类对象时,到底调用哪个方法,由对象自己的“真实”类型所决定,这就是说:对象是子类型的,它就调用子类型的方法,是父类型的,它就调用父类型的方法。
这个特性实际上就是面向对象“多态”特性的具体表现。
(2)如果子类与父类有相同的字段,则子类中的字段会代替或隐藏父类的字段,子类方法中访问的是子类中的字段(而不是父类中的字段)。如果子类方法确实想访问父类中被隐藏的同名字段,可以用super关键字来访问它。
如果子类被当作父类使用,则通过子类访问的字段是父类的!
牢记:(验证结论发博客)
在实际开发中,要避免在子类中定义与父类同名的字段。不要自找麻烦!——但考试除外,考试中出这种题还是可以的。