做梦都要背出来的三个必要条件
代码实例
package cn.haien.polymorphism;
public class Animal {
    public void voice() {
        System.out.println("普通动物的叫声");
    }
}
class Cat extends Animal{
    public void voice() {
        System.out.println("喵喵喵");
    }
    public void catchMouse() {
        System.out.println("抓老鼠");
    }
}
class Dog extends Animal{
    public void voice() {
        System.out.println("汪汪汪");
    }
}
package cn.haien.polymorphism;
public class Test {
    public static voidtestAnimalVoice(Animal c) {//形参使用多态
    //编译时,扫描到Animal
                                              //并发现其中有voice这个方法就通过了
        c.voice();
    if(c instanceof Cat)//instanceof 表示判断前者是不是后面类的实例化对象
        ((Cat)c).catchMouse();//如果是的话,强制转换为Cat类型并调用它自己的方法
    }
public static void main(String[] args) {
    Animal a = new Cat();
    Animal b = new Dog();
    testAnimalVoice(a);
    testAnimalVoice(b);
    Cat a2 = (Cat)a;//只能把引用该子类的父类对象强制转换为相应子类,其他都不行
    //Cat b2 = (Cat)b;
    a2.catchMouse();
    //b2.catchMouse();//编译通过,但运行出错,编译通过是因为编译器比较傻,你让它强制转换为什么它就强制转换为什么
                    //但是真正运行的时候实际是什么就是什么,不能把一只狗强制转换为一只猫
}
}
其实返回值也可以使用多态
内存分析
- 编译文件,从上到下、从左到右开始扫描,首先将Test加载到方法区即帧中(在Test文件中点运行)
 - 扫描到main方法则开始运行
 - 遇到类名则将其加载到帧中
 遇到new则创建对象并在栈中分配内存,那么要先调用类的构造器。
PS:构造器中实际隐式地传入this和supper,,而supper指向上级父类,一直找到Object类后开始一级一级往下执行构造器,每一级的this都指向最终要创建的对象而不会不同,只有supper是不同的
- 遇到testAnimalVoice方法开始传参,开辟栈帧存放形参c,同样指向堆中的类构造
 
内存情况
            内存深入分析
package cn.haien.polymorphism2;
public class HttpServlet {
    public void service() {
        System.out.println("HttpServlet.service()");
        doGet();//实际上是this.doGet();
    }
    public void doGet() {
        System.out.println("HttpServlet.doGet()");
    }
}
class myServlet extends HttpServlet{
    public void doGet() {
        System.out.println("myServlet.doGet()");
    }
}
package cn.haien.polymorphism2;
public class TestHttpServlet {
    public static void main(String[] args) {
        HttpServlet a = new myServlet();
        a.service();//内含doGet的调用,实际上调用的是子类myServlet的doGet函数
    }
}