分析JAVA、C#、C++的“覆盖”和“隐藏”与多态的实现
隐藏字段 :字段不可以被覆盖而只能被隐藏。
可访问性与覆盖 :一个方法只有当它可以被访问时才可以被覆盖。
隐藏静态成员 :类中的静态成员(无论是字段还是方法)不可以被覆盖,只能被隐藏。
由以上可推出,JAVA中基类与子类若有同签名的函数,则基类中的此函数一定要被子类覆盖掉,相应地基类中的此函数也一定不能为private,理由根据上述第二点。而C#中却不必如此,在这点上C#做得要显明得多,即基类方法加virtual关键字,而子类方法再override表示覆盖,加new关键字表示隐藏。在这一点上,C#与C++相似,在C++中,若基类方法加了virtual关键字,则子类方法的继承规则是“覆盖”,若基类方法无virtual关键字,则为“隐藏”。即C#与C++的默认方式都是隐藏,即都会把基类的方法拷贝一份过来,除非使用关键字显示告诉编译器我要覆盖。这一点在功能上来说,JAVA显得不到位,因为它无法做到“隐藏”这一功能,即同签名的基类方法子类无法再拥有。所以:多态只不过就是实现了“覆盖”,当实现了“覆盖”,虽然是基类类型,但因为子类的方法将基类的方法覆盖掉了,所以以“基类类型.方法名()”的方式去调用时,内存中只存在被子类所覆盖重写的方法,即实现了多态“根据运行期实际的对象调用其方法,而不是只根据其类型”。
理解以上原则后再去探究一下以下代码:
import java.io.*;
class A{
static String s1 ="staticA";
String s2 = "A";
static void getString1() {
System.out.println(s1);
}
void getString2() {
System.out.println(s2);
}
}
class B extends A {
static String s1="staticB";
String s2 = "B";
static void getString1() {
System.out.println(s1);
}
void getString2() {
System.out.println(s2);
}
}
public class test01 {
public static void main(String[] args) {
A a = new B();
System.out.println("a.s1="+a.s1);
System.out.println("a.s2="+a.s2);
a.getString1();
a.getString2();
}
}
// 运行结果:
// a.s1=staticA//字段不可以被覆盖而只能被隐藏。即字段无法实现多态
// a.s2=A//同上
// staticA//静态成员(不管是字段还是方法)不可以被覆盖而只能被隐藏。即静态成员无法实现多态
// B//普通方法被覆盖,实现了多态