新手上路!!!!
我们的java课本中有这样一个例子,看完之后觉得特别迷惑,就查了点资料。
class Super
{
}
class Sub extends Super
{
}
public class PolyConstructors {
}
输出结果是:
how are you, liming
迷惑点1:生成的实例s到底是基类还是子类的实例?
2:问什么会有这样的输出结果,即调用了父类的方法,有调用了子类的方法?
解:1.生成的实例是子类的,只是他被强制类型转换成父类的类型了。
2.在java中,类方法被隐藏,实例方法被覆盖。
个人理解:
因为实例方法被覆盖,而静态方法只是被隐藏了。所以在Sub()中其实有三个方法,一个是Super类的greeting()方法,一个是Sub类的greeting()方法和name()方法。实
例化的s是Sub类的,但是他被强制类型转换成了父类类型的,所以在调用greeting()和name()方法时,分别调用的是Super()类的greeting()和Sub类的name(),这才有最终的运
行结果!
权威解释(网上当的,课本也是这样说的):
super类由方法 greeting和name组成,Sub 类继承了 Super 类,而且同样含有 greeting 和 name方法。Test 类只有一个 main方法。在 Test 类中,我们创建了一个 Sub 类
的实例。在这里,你必须明白的是:虽然变量 s的数据类型为 Super 类,但是它仍旧是 Sub 类的一个实例。
关键问题是,我们调用的到底是Super类的方法还是Sub类的方法,让我们首先判断调用的是哪个类的name()方法,两个类中的name()方法都不是静态方法,而是实例方法,因为
Sub类继承了Super类,而且有一个和它父类同样标识的name()方法,所以Sub类中的name() 方法覆盖了Super类中的name()方法,那么前面提到的变量s又是Sub 类的一个实例,
这样一来 s.name()的返回值就是“Dick”了。
现在我们需要判断被调用的greeting()方法究竟是Super类的还是Sub类的。需要注意的是,两个类中的greeting()方法都是静态方法,也称为类方法。尽管事实上Sub类的
greeting()方法具有相同的返回类型、相同的方法名以及相同的方法参数。然而它并不覆盖Super类的greeting()方法,由于变量s被强制转换为Super型并且Sub类的greeting()
方法没有覆盖Super类的greeting()方法,因此 s.greeting()的返回值为Goodnight。
还是很迷惑?请记住这条规则:“实例方法被覆盖,静态方法被隐藏”。
现在你可能会问“隐藏和覆盖有什么区别”你也许还未理解这点。然而实际上我们刚刚在这个Super/Sub 类的例子中已经解释了两者的不同。使用类的全局名可以访问被隐藏的
方法,即使变量s是Sub类的一个实例,而且Sub类的greeting()方法隐藏了Super 类的同名方法,我们仍旧能够将s强制转换为Super型以便访问被隐藏的greeting()方法,与被
隐藏的方法不同,对被覆盖的方法而言,除了覆盖它们的类之外,其他任何类都无法访问它们。这就是为何变量s调用的是Sub类的name(),而非Super类的name()方法。
实例方法被覆盖而静态方法被隐藏,被覆盖的方法只有覆盖它们的类才能访问它们,而访问被隐藏的方法的途径是提供该方法的全局名。
--试图用子类的静态方法隐藏父类中同样标识的实例方法是不合法的,编译器将会报错
--试图用子类的实例方法覆盖父类中同样标识的静态方法也是不合法的,编译器会报错
--静态方法和最终方法(带关键字final的方法)不能被覆盖
--实例方法能够被覆盖
--抽象方法必须在具体类中被覆盖