一.多态的三个条件
1.继承 2.子类重写父类方法 3.父类引用指向子类对像
二.继承的等价写法
父类,子类定义如下:
class Father{
void test()
{
System.out.println("Father test");
}
}
class Son extends Father{
void test2()
{
System.out.println("Son test2");
}
}
子类Son继承了父类Father,并且Son有了自己的方法test2,则Son的等价写法如下:
class Son {//此处去掉了继承Father,
//此Son的等价写法,是为了说明继承后,子类Son中都有什么方法可用
void test()
{
System.out.println("Father test");
}
void test2()
{
System.out.println("Son test2");
}
}
Son的等价写法不难理解,这样写,是为了引出多态中父类的等价写法,这样,可以更明确的知道,父类都有什么方法可以调用
三.多态的等价写法
父类,子类的定义如下,子类重写了父类的方法:
class Father{
void test()
{
System.out.println("Father test");
}
void test2()
{
System.out.println("Father test2");
}
}
class Son extends Father{
void test()
{
System.out.println("Son test");
}
void test3()
{
System.out.println("Son test3");
}
}
父类中有test()和test2()两个方法,子类中重写了父类的test()方法,添加了自己的方法test3()
调用:Father fa=new Son(); fa.test();
输出:Son test
继承,重写test(),父类指向子类对象,形成多态,输出“Son test”
A. 那么,多态情况下,父类的等价写法,如下:
class Father{
void test()//多态子类重写的test()覆盖了父类的方法test()
{
System.out.println("Son test");
}
void test2()
{
System.out.println("Father test2");
}
}
这就相当于,在形成多态的情况下,父类中的方法,被子类中的重写的方法被覆盖。
特别说明下:这个只是多态下,父类的等价写法而已,并不是父类的真实代码,多态是在运行的时候动态调用的子类的重写方法,编译的时候,父类还是原来的代码。
多态下父类的等价写法,可以这样理解:相当于,多态下,子类的方法上行传递给了父类,覆盖了父类的代码。
也就是,子类重写的方法,test()覆盖了父类的方法test()
可以和继承做个比较,继承是父类方法,下行,传递给了子类。
B.同一代码,继续时候,子类的等价代码如下:
class Son {
void test()//子类重写的方法,覆盖了父类方法
{
System.out.println("Son test");
}
void test2()//子类继承的父类方法test2
{
System.out.println("Father test2");
}
void test3()//子类自己定义的自己特有的方法,跟父类一毛钱关系都没有
{
System.out.println("Son test3");
}
}
之所以,改写为等价写法,是把子类和父类,拆了两个独立的没关系的个体。这样,可以明确知道,实例对象,调用的是哪个方法。
三.小结
1.多态下,父类的等价写法,可以看成,子类方法上行传递覆盖了父类的方法。
2.继承的等价写法,可以看出,父类方法下行传递给了子类方法。
3.拆成了等价写法,可以看成父类子类是两个没关系的独立的类,可以方便的看出,对象指向的是哪个类,就明确了,方法的内容。
四.举个栗子
有如下三个类,继承关系如下:
class ClassA{
void show(){
show2();
}
void show2(){
System.out.println("ClassA show2");
}
}
class ClassB extends ClassA{
void show2(){
System.out.println("ClassB show2");
}
}
class ClassC extends ClassB{
void show()
{
super.show();
}
void show2(){
System.out.println("ClassC show2");
}
}
测试代码:ClassB b=new ClassC(); b.show();
1. b指向子类ClassC的对象,调用的是ClassC里的 show()
2. ClassC里show(),调用super.show(),这里super指向ClassB的父类ClassA的对象
3.调用了从ClassA里面继承过来的show()方法
4.ClassB的show()方法调用 show2()
到这里问题来了,到底应该调用哪个类里的show2()方法呢?
先绕个弯分析一下,哪个方法符合多态
1.show方法是否有多态
- ClassB继承了ClassA,没有重写show(),所以此处没有多态
- ClassC继承了ClassB,重写了show(),可以形成多态
2.show2()的多态情况
- ClassB继承了ClassA,重写了show2(),可以形成多态
- ClassC继承了ClassB,重写了show2(),可以形成多态
可以看出,show2()形成了多态,所以最终,都是调用的ClassC中重写的show2()
所以,输出为:ClassC show2
以下,看下等价类分析结果:
ClassA,ClassB,ClassC在多态情况下的等价写法,也包括继承的等价写法:
class ClassA{
void show(){
show2();
}
void show2(){
System.out.println("ClassC show2");
}
}
class ClassB {
void show()
{
super.show();
}
void show2(){
System.out.println("ClassC show2");
}
}
class ClassC {
void show()
{
super.show();
}
void show2(){
System.out.println("ClassC show2");
}
}
这样把三个类看成三个独立的类,可以看出 各自的对象可以调用哪些方法:(由于,看成独立的类,super得单独指向父类)
CalssC:重写了ClassB的show(),和show2()
ClassB: ClassB的继承的show()和自己的show2()由于形成重写,被子类CalssC重写的方法覆盖
ClassA:ClassB中没有重写show(),未形成多态,所以,ClassA仍是原来自己的show()
ClassB中重写了show2(),形成多态,所以,上行覆盖ClassA的show2()
而CalssC又重写了ClassB的show2(),形成多态,所以,上行传递,覆盖了ClassA和ClassB的show2()
这样,可以从三个等价类,看出 b.show()可以调用过程。
1. b.show()调用了super.show()
2.super.show()指向了ClassA的show()
3.ClassA的show()调用了ClassA的show2()
输出为:ClassC show2