基本介绍

方法或对象具有多种形态。是面向对象的第三大特征,多态是建立在封装和继承基础之上的。

多态的具体体现

  1. 方法的多态:重写和重载就体现多态.
  2. 对象的多态(重点) ```java public class Animal { public void cry() {
    1. System.out.println("Animal cry() 动物在叫....");
    } }

public class Cat extends Animal { public void cry() { System.out.println(“Cat cry() 小猫喵喵叫…”); } }

public class Dog extends Animal { public void cry() { System.out.println(“Dog cry() 小狗汪汪叫…”); } }

public class PolyObject { public static void main(String[] args) { //体验对象多态特点 //animal 编译类型就是 Animal , 运行类型 Dog Animal animal = new Dog(); //因为运行时 , 执行到改行时,animal 运行类型是 Dog,所以 cry 就是 Dog 的 cry animal.cry(); //小狗汪汪叫 //animal 编译类型 Animal,运行类型就是 Cat animal = new Cat(); animal.cry(); //小猫喵喵叫 } }



<a name="1ccfe472"></a>
## 编译类型和运行类型

1. 一个对象的编译类型和运行类型可以不一致
2. 编译类型在定义对象时,就确定了,不能改变
3. 运行类型是可以变化的.
4. 编译类型看定义时=号的左边,运行类型看=号的右边

<a name="fb21c157"></a>
## 多态注意事项和细节

1.  多态的**前提**是:两个对象(类)存在继承关系 
2.  多态的向上转型 
-  本质:父类的引用指向了子类的对象 
-  语法: `父类类型 引用名 = new 子类类型();`
- 特点:**编译类型看左边,运行类型看右边**。可以调用父类中的所有成员(需遵守访问权限),**不能调用子类中特有成员;最终运行效果看子类的具体实现**! 
3. 多态向下转型
-  语法: `子类类型 引用名 = (子类类型) 父类引用;`
-  只能强转父类的引用,不能强转父类的对象。 
-  要求父类的引用必须指向的是当前目标类型的对象。 
-  当向下转型后,可以调用子类类型中所有的成员。 

示例代码:
```java
public class Animal {
    String name = "动物";
    int age = 10;
    public void sleep(){
        System.out.println("睡");
    }
    public void run(){
        System.out.println("跑");
    }
    public void eat(){
        System.out.println("吃");
    }
    public void show(){
        System.out.println("hello,你好");
    }
}

public class Cat extends Animal {
    public void eat(){//方法重写
        System.out.println("猫吃鱼");
    }
    public void catchMouse(){//Cat 特有方法
        System.out.println("猫抓老鼠");
    }
}

public class Dog extends Animal {}

public class PolyDetail {
    public static void main(String[] args) {
        //向上转型: 父类的引用指向了子类的对象
        Animal animal = new Cat();
        Object obj = new Cat();//可以吗? 可以。Object 也是 Cat 的父类
        //animal.catchMouse();错误
        //最终运行效果看子类(运行类型)的具体实现, 即调用方法时,按照从子类(运行类型)开始查找方法然后调用
        animal.eat();//猫吃鱼.. animal.run();//跑
        animal.show();//hello,你好
        animal.sleep();//睡

        //多态的向下转型
        Cat cat = (Cat) animal;
        cat.catchMouse();//猫抓老鼠
        //要求父类的引用必须指向的是当前目标类型的对象
        Dog dog = (Dog)animal; //可以吗?不可以
        System.out.println("ok~~");
    }
}
  1. 属性没有重写之说!属性的值看编译类型 ```java public class PolyDetail02 { public static void main(String[] args) {
     //属性没有重写之说!属性的值看编译类型
     Base base = new Sub();//向上转型
     System.out.println(base.count);// ? 看编译类型 10
     Sub sub = new Sub();
     System.out.println(sub.count);//? 20
    
    } }

class Base { //父类 int count = 10;//属性 }

class Sub extends Base {//子类 int count = 20;//属性 }



5.  `instanceOf` 比较操作符,**用于判断对象的运行类型是否为 XX 类型或 XX 类型的子类型**
```java
public class PolyDetail03 {
    public static void main(String[] args) {
        BB bb = new BB();
        System.out.println(bb instanceof BB);// true
        System.out.println(bb instanceof AA);// true

        //aa 编译类型 AA, 运行类型是 BB
        //BB 是 AA 子类
        AA aa = new BB();
        System.out.println(aa instanceof AA);// true
        System.out.println(aa instanceof BB);// true
        Object obj = new Object();
        System.out.println(obj instanceof AA);//false
        String str = "hello";
        //System.out.println(str instanceof AA);
        System.out.println(str instanceof Object);//true
    }
}

class AA {} //父类
class BB extends AA {}//子类

java 的动态绑定机制(重要)

Java 重要特性: 动态绑定机制
image.png

示例代码:

public class DynamicBinding {
    public static void main(String[] args) {
        //a 的编译类型 A, 运行类型 B
        A a = new B();//向上转型
        System.out.println(a.sum());//?40 -> 30
        System.out.println(a.sum1());//?30-> 20
    }
}

class A {//父类
    public int i = 10;
    //动态绑定机制:
    public int sum() {//父类 sum()
        return getI() + 10;//20 + 10
    }
    public int sum1() {//父类 sum1()
        return i + 10;//10 + 10
    }
    public int getI() {//父类 getI
        return i;
    }
}

class B extends A {//子类
    public int i = 20;
    // public int sum() {
    //     return i + 20;
    // }
    public int getI() {//子类 getI()
        return i;
    }
    // public int sum1() {
    //     return i + 10;
    // }
}