封装、继承、多态是面向对象编程中三个比较重要的概念,理解这3个概念对领会JAVA语言至关重要,而搞懂方法的覆盖又是理解继承的关键部分,这里解释“实例方法被覆盖,静态方法被隐藏”的概念。
首先看一段代码:
class Super {
static String greeting(){
return "Good night";
}
String name(){
return "Richard";
}
}
class Sub extends Super {
static String greeting(){
return "Hello";
}
String name(){
return "Dick";
}
}
public class MyTest {
public static void main(String args[]) {
Super s1 = new Super();
Sub s2 = new Sub();
Super s3 = new Sub();
System.out.println(s1.greeting()+ ","+s1.name());
System.out.println(s2.greeting()+ ","+s2.name());
System.out.println(s3.greeting()+ ","+s3.name());
}
}
运行Test 类的结果为:
Good night,Richard
Hello,Dick
Good night,Dick
这里greeting()是静态方法,name()是实例方法。
因为Sub 类继承了Super 类而且有一个和它父类同样标识的name()方法,所以Sub 类中的name()方法覆盖了Super 类中的name()方法。变量s2和s3 是Sub 类的一个实例,所以s2.name()和s3.name()的返回值是Dick 。
两个类中的greeting()方法都是静态方法,也称为类方法。尽管事实上Sub 类的greeting()方法具有相同的返回类型、相同的方法名以及相同的方法参数,然而它并不覆盖Super 类的greeting()方法,只是隐藏它。变量s3 被强制转换为Super 型并且Sub 类的greeting()方法没有覆盖Super 类的greeting()方法,因此s3.greeting()的返回值为Goodnight 。
与被隐藏的方法不同,对被覆盖的方法而言,除了它们本身所在的类之外其他任何类都无法访问它们。如要打印Richard,就只能用Super 类的实例s1。
需要注意的几点:
1. 试图用子类的静态方法隐藏父类中同样标识的实例方法是不合法的,编译器将会报错;
2. 试图用子类的实例方法覆盖父类中同样标识的静态方法也是不合法的,编译器同样会报错;
3. 静态方法和最终方法(带关键字final 的方法)不能被覆盖;
4. 实例方法能够被覆盖;
5. 抽象方法必须在具体类中被覆盖。