- class Super
- {
- static String greeting() {
- return "Goodnight";
- }
- String name() {
- return "Richard";
- }
- }
- class Sub extends Super
- {
- static String greeting(){
- return "Hello";
- }
- String name(){
- return "Dick";
- }
- }
- public class PolyConstructors {
- public static void main(String[] args){
- Super s = new Sub();
- System.out.println(s.greeting() + ", " + s.name());
- }
- }
class Super
{
static String greeting() {
return "Goodnight";
}
String name() {
return "Richard";
}
}
class Sub extends Super
{
static String greeting(){
return "Hello";
}
String name(){
return "Dick";
}
}
public class PolyConstructors {
public static void main(String[] args){
Super s = new Sub();
System.out.println(s.greeting() + ", " + s.name());
}
}
输出结果是:
- Goodnight, Dick
Goodnight, Dick
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的方法)不能被覆盖
--实例方法能够被覆盖
--抽象方法必须在具体类中被覆盖