Java多态

 一、多态
(1)多态是指允许不同类的对象对同一消息作出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式。
     (多态是同一个行为具有多个不同表现形式或形态的能力。
      多态就是同一个接口,使用不同的实例而执行不同操作,
      例子:①
Java多态
②  现实中,比如我们按下 F1 键这个动作:
- 如果当前在 Flash 界面下弹出的就是 AS 3 的帮助文档;
- 如果当前在 Word 下弹出的就是 Word 帮助;
- 在 Windows 下弹出的就是 Windows 帮助和支持。
同一个事件发生在不同的对象上会产生不同的结果。

       多态也称为动态绑定(dynamic binding),是指在执行期间判断所引用对象的实际类型,根据其实际的类型调用其响应的方法。
      通俗地讲,只通过父类就能够引用不同的子类,这就是多态,我们只有在运行的时候才会知道引用变量所指向的具体实例对象。

(2)优点:《1》消除类型之间的耦合关系 《2》可替换性 《3》可扩充性 《4》接口性 《5 》灵活性 《6》简化性

二、向上转型
(1)例如:Animal 是父类 , Dog是子类
Animal a = new Animal(); //a是父类的引用指向的是本类的对象
Animal b = new Dog(); //b是父类的引用指向的是子类的对象
        注意:不能用一个子类的引用去指向父类的对象。
  (2)指向子类对象的父类引用类型,能够引用父类中定义的所有属性和方法,还可以使用子类强大的功能(即对父类方法进行重写后的方法),但对于只存在于子类的方法和属性就不能获取。
总结: 向上转型(指向子类对象的父类引用类型 ),在运行时,会遗忘子类对象中与父类对象中不同的方法,也会覆盖与父类中相同的方法——重写。
(当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,再去调用子类的同名方法。)

三、多态的实现
1、多态的实现条件继承、重写和向上转型(即父类引用指向子类对象)
2、多态的实现方法:继承父类进行方法重写,抽象类和抽象方法,接口实现
(1)抽象类和抽象方法
《1》 Java提供了一个叫做抽象方法的机制,这种方法是不完整的,仅有声明而没有方法体。
抽象方法声明语法:
abstract void f(); // f()是抽象方法
 《2》包含抽象方法的类叫做抽象类,抽象类在定义时,前面会加abstract关键字
 《3》使用抽象类的情况:
         ① 在某些情况下,某个父类只是知道其子类应该包含怎样的方法,但无法准确知道这些子类如何实现这些方法。即抽象类是约束子类必须要实现哪些方法,而并不关注方法如何实现。
        ② 从多个具有相同特征的类中抽象出一个抽象类,以这个抽象类作为子类的模板,从而避免了子类设计的随意性。
《4》如何实现抽象类:
       ① 用 abstract 修饰符定义抽象类
       ② 用abstract 修饰符定义抽象方法,只需要声明,不需要实现
       ③ 抽象类可以包含普通的方法,也可以没有抽象方法
       ④ 抽象类的对象不能直接创建,通常是定义引用变量指向子类对象 
(2)接口实现
  《1》interface会产生一个完全抽象类,根本没有提供任何方法体。
接口的声明语法格式:
修饰符 interface 接口名称 [extends 其他的类名] {
     // 声明变量
     // 抽象方法
}
例如:
interface Animal {
     //int x; //编译错误,x需要初始化,因为是 static final 类型
     int y = 5;
     public void eat(); public void travel();
}
注意:① 接口不能用于实例化对象
         ② 接口中所有的方法都是抽象方法
         ③ 接口成员是static final类型
         ④ 接口支持多继承
多继承实现方式:
修饰符 interface A extends 接口1,接口2{
}
修饰符 class A implements 接口1,接口2{
}

四、虚方法
例子: Employee是父类,有个方法 mailCheck() ; Salary是子类,重写了父类的方法mailCheck();
/* 文件名 : VirtualDemo.java */
public class VirtualDemo {
public static void main(String [] args) {
Salary s = new Salary("员工 A", "北京", 3, 3600.00);
Employee e = new Salary("员工 B", "上海", 2, 2400.00);
System.out.println("使用 Salary 的引用调用 mailCheck -- ");
s.mailCheck();
System.out.println("\n使用 Employee 的引用调用 mailCheck--");
e.mailCheck();
}
}
例子解析:
(1) 实例中,实例化了两个 Salary 对象:一个使用 Salary 引用 s,另一个使用 Employee 引用 e。
(2)当调用 s.mailCheck() 时,编译器在编译时会在 Salary 类中找到 mailCheck(),执行过程 JVM 就调用 Salary 类的 mailCheck()。
(3) 因为 e 是 Employee 的引用,所以调用 e 的 mailCheck() 方法时,编译器会去 Employee 类查找 mailCheck() 方法 。在编译的时候,编译器使用 Employee 类中的 mailCheck() 方法验证该语句, 但是在运行的时候,Java虚拟机(JVM)调用的是 Salary 类中的 mailCheck() 方法。
以上整个过程被称为虚拟方法调用,该方法被称为虚拟方法。