面向对象编程有三个特征,即封装、继承和多态。
封装隐藏了类的内部实现机制,从而可以在不影响使用者的前提下改变类的内部结构,同时保护了数据。
继承是为了重用父类代码,同时为实现多态性作准备。那么什么是多态呢?
要理解多态性,首先要知道什么是“向上转型”。
我定义了一个子类Cat,它继承了Animal类,那么后者就是前者是父类。我可以通过
Cat c = new Cat();
实例化一个Cat的对象,这个不难理解。但当我这样定义时:
Animal a = new Cat();
这代表什么意思呢?
很简单,它表示我定义了一个Animal类型的引用,指向新建的Cat类型的对象。由于Cat是继承自它的父类Animal,所以Animal类型的引用是可以指向Cat类型的对象的。那么这样做有什么意义呢?因为子类是对父类的一个改进和扩充,所以一般子类在功能上较父类更强大,属性较父类更独特,
定义一个父类类型的引用指向一个子类的对象既可以使用子类强大的功能,又可以抽取父类的共性。
所以,父类类型的引用可以调用父类中定义的所有属性和方法,而对于子类中定义而父类中没有的方法,它是不能调用的;(但是如果强制把超类转换成子类的话,就可以调用子类中新添加而超类没有的方法了。)
同时,父类中的一个方法只有在在父类中定义而在子类中没有重写的情况下,才可以被父类类型的引用调用;
换个说法 : 如果子类重写了父类的定义的方法,父类类型的引用调用的则是子类的方法 这就是动态连接。
例子
class Father {
void fun1(){
fun2();
}
void fun2(){
}
}
class Child extends Father {
void fun1(int i){
System.out.println("func1 in Child");
}
void fun2(){
System.out.println("func2 in Child");
}
}
public class Main {
public static void main(String[] args) {
Father child = new Child();
child.fun1();
}
结果是显示 func2 in Child
解析
因为 类Child 没有重写了 类Father 的 fun1(),所以会调用父类的 fun1()。而在 父类的 fun1() 中,会调用子类的 fun2(),这是因为子类重写了 fun2(),将父类的 fun2() “屏蔽”掉了。
解析对应上文红字部分
例二:
class A {
public String show(D obj) {
return ("A and D");
}
public String show(A obj) {
return ("A and A");
}
}
class B extends A {
public String show(B obj) {
return ("B and B");
}
public String show(A obj) {// 重写父类的函数
return ("B and A");
}
public String show() {// 重写父类的函数
return ("show in Class B");
}
}
class C extends B {
}
class D extends B {
}
public class Main {
public static void main(String[] args) {
A a1 = new A();
A a2 = new B();
B b = new B();
C c = new C();
D d = new D();
System.out.println(a1.show(b));
System.out.println(a1.show(c));
System.out.println(a1.show(d));
System.out.println("********************");
System.out.println(a2.show(b));
System.out.println(((B) a2).show(b));
System.out.println(a2.show(c));
System.out.println(a2.show(d));
System.out.println("********************");
System.out.println(b.show(b));
System.out.println(b.show(c));
System.out.println(b.show(d));
}
}
结果如下
分析:
部分摘自http://blog.youkuaiyun.com/thinkGhoster/article/details/2307001
方法调用的优先问题 ,优先级由高到低依次为:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。让我们来看看它是怎么工作的。
a1 是 A 的一个对象引用,调用 类 A 的show() 会根据传入的参数 ,函数会发生重载。若传入 D的实例,则会显示 “ A AND D” .若传入 A 的实例,或者 A 的子类的
实例,则会输出 “A AND A ”.
a2 是 A 的一个引用,却指向一个 B 的对象(B 是 A 的子类)。a2 调用 show()时,先会看父类中有无该函数,该函数如果没有被子类重写,则执行父类的函数,否则执行子类的函数。
a2.show(b) ,类 A 中存在该函数 show(A a),但是 在子类 B 中被重写了,故 执行 类B 的 show(A a)。输出 B AND A. 下面以方法调用顺序说明
a2 对应 this 应该为 A, O 对应b. (super)O 就是对应 A.
a2.show(b) 类 A 中 没有show(B b),====》类A没有super=======>A.show((super)O) 即 A.show(A a) 但是发现类B 重写了该方法,故执行 B.show(A a).
a2.show(c)
a2 对应 this 应该为 A, O 对应c. (super)O 就是对应 B.
a2.show(c) 类 A 中 没有show(C c),====》类A没有super=======>A.show((super)O) 即 A.show(B b) 刚刚我们知道 A.show(B b)显示 B AND A.