【Java】多态学习笔记

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Xumuyang_/article/details/90476916

一、什么是多态❓

我们都知道,面向对象编程有三大特性:继承、封装、多态。

继承👉继承是Java面向对象编程技术的一块基石,因为它允许创建分等级层次的类。
   继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。

封装👉封装是指一种将抽象性函数接口的实现细节部分包装、隐藏起来的方法。
   封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问。要想访问该类的代码和数据,必须通过严格的接口控制。
   封装最主要的功能在于我们能修改自己的实现代码,而不用修改那些调用我们代码的程序片段。适当的封装可以让代码更容易理解和维护,也加强了代码的安全性。

多态👉 所谓多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量到底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。

简言之:多态是同一个行为具有多个不同表现形式或形态的能力。也就是同一个接口,使用不同的实例而执行不同操作。

举例👇:

比如我们按下 F1 键这个动作:

1、如果当前在 Flash 界面下弹出的就是 AS 3 的帮助文档;
2、如果当前在 Word 下弹出的就是 Word 帮助;
3、在 Windows 下弹出的就是 Windows 帮助和支持。

同一个事件发生在不同的对象上会产生不同的结果。

二、什么是动态绑定

实现多态的技术称为动态绑定,也叫值绑定或多态。它是指在执行期间判断所引用对象的实际类型,根据其实际类型调用其相应的方法。

作用:消除类型之间的耦合关系。

三、多态存在的三个必要条件

这个非常重要,重要到做梦时都能背出来!

1、要有继承:在多态中必须存在有继承关系的子类和父类;

2、要有重写:子类对父类中某些方法进行重新定义,在调用这些方法时就会调用子类的方法;

3、父类引用指向子类对象(即向上转型):在多态中,需要将子类的引用赋给父类对象,
                                 只有这样,该引用才能够具备技能调用父类的方法和子类的方法。

举例说明👇

Parent p = new Child();

当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,再去调用子类的同名方法。

多态的好处:可以使程序有良好的扩展,并可以对所有类的对象进行通用处理。

下面是一个多态实例👇:

public class Test {
    public static void main(String[] args) {
      show(new Cat());  // 以 Cat 对象调用 show 方法
      show(new Dog());  // 以 Dog 对象调用 show 方法
                
      Animal a = new Cat();  // 向上转型  
      a.eat();               // 调用的是 Cat 的 eat
      Cat c = (Cat)a;        // 向下转型  
      c.work();        // 调用的是 Cat 的 work
  }  
            
    public static void show(Animal a)  {
      a.eat();  
        // 类型判断
        if (a instanceof Cat)  {  // 猫做的事情 
            Cat c = (Cat)a;  
            c.work();  
        } else if (a instanceof Dog) { // 狗做的事情 
            Dog c = (Dog)a;  
            c.work();  
        }  
    }  
}
 
abstract class Animal {  
    abstract void eat();  
}  
  
class Cat extends Animal {  
    public void eat() {  
        System.out.println("吃鱼");  
    }  
    public void work() {  
        System.out.println("抓老鼠");  
    }  
}  
  
class Dog extends Animal {  
    public void eat() {  
        System.out.println("吃骨头");  
    }  
    public void work() {  
        System.out.println("看家");  
    }  
}

执行以上程序,输出结果为👇:

吃鱼
抓老鼠
吃骨头
看家
吃鱼
抓老鼠

四、多态的好处

1)可替换性(substitutability):多态对已存在代码具有可替换性。例如,多态对圆Circle类工作,对其他任何圆形几何体,如圆环,也同样工作。

2)可扩充性(extensibility):多态对代码具有可扩充性。增加新的子类不影响已存在类的多态性、继承性,以及其他特性的运行和操作。实际上新加子类更容易获得多态功能。例如,在实现了圆锥、半圆锥以及半球体的多态基础上,很容易增添球体类的多态性。

3)接口性(interface-ability):多态是超类通过方法签名,向子类提供了一个共同接口,由子类来完善或者覆盖它而实现的。

4)灵活性(flexibility):多态在应用中体现了灵活多样的操作,提高了使用效率。

5)简化性(simplicity):多态简化对应用软件的代码编写和修改过程,尤其在处理大量对象的运算和操作时,这个特点尤为突出和重要。

五、多态的实现方式

1、重写
  1)重写是子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变。即外壳不变,核心重写。

  2)重写的好处在于子类可以根据需要,定义特定于自己的行为。 也就是说子类能够根据需要实现父类的方法。

  3)重写方法不能抛出新的检查异常或者比被重写方法申明更加宽泛的异常。例如: 父类的一个方法申明了一个检查异常 IOException,但是在重写这个方法的时候不能抛出 Exception 异常,因为 Exception 是 IOException 的父类,只能抛出 IOException 的子类异常。

举例👇

class Animal{
   public void move(){
      System.out.println("动物可以移动");
   }
}
 
class Dog extends Animal{
   public void move(){
      System.out.println("狗可以跑和走");
   }
}
 
public class TestDog{
   public static void main(String args[]){
      Animal a = new Animal(); // Animal 对象
      Animal b = new Dog(); // Dog 对象
 
      a.move();// 执行 Animal 类的方法
 
      b.move();//执行 Dog 类的方法
   }
}

运行结果:

动物可以移动
狗可以跑和走

注:方法的重写规则👇

1)参数列表必须完全与被重写方法的相同。
2)返回类型与被重写方法的返回类型可以不相同,但是必须是父类返回值的派生类(java5 及更早版本返回类型要一样,
   java7 及更高版本可以不同)。
3)访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类的一个方法被声明为public,
   那么在子类中重写该方法就不能声明为protected。
4)父类的成员方法只能被它的子类重写。
5)声明为final的方法不能被重写。
6)声明为static的方法不能被重写,但是能够被再次声明。
7)子类和父类在同一个包中,那么子类可以重写父类所有方法,除了声明为private和final的方法。
8)子类和父类不在同一个包中,那么子类只能够重写父类的声明为public和protected的非final方法。
9)重写的方法能够抛出任何非强制异常,无论被重写的方法是否抛出异常。但是,重写的方法不能抛出新的强制性异常,
   或者比被重写方法声明的更广泛的强制性异常,反之则可以。
10)构造方法不能被重写。
11)如果不能继承一个方法,则不能重写这个方法。

2、接口
  1)生活中的接口最具代表性的就是插座。例如,一个三接头的插头都能接在三孔插座中,因为这个是每个国家都有各自规定的接口规则,有可能到国外就不行,纳士因为国外自己定义的接口类型。

  2)Java中的接口类似于生活中的接口,就是一些方法特征的集合,但没有方法的实现。

举例说明👇

当类实现接口的时候,类要实现接口中所有的方法。否则,类必须声明为抽象的类。

类使用implements关键字实现接口。在类声明中,Implements关键字放在class声明后面。

实现一个接口的语法,可以使用这个公式:

...implements 接口名称[, 其他接口名称, 其他接口名称..., ...] ...

例子:

/* 文件名 : MammalInt.java */
public class MammalInt implements Animal{
 
   public void eat(){
      System.out.println("Mammal eats");
   }
 
   public void travel(){
      System.out.println("Mammal travels");
   } 
 
   public int noOfLegs(){
      return 0;
   }
 
   public static void main(String args[]){
      MammalInt m = new MammalInt();
      m.eat();
      m.travel();
   }
}

运行结果👇

Mammal eats
Mammal travels

注:实现接口时,要注意👇:

1)一个类可以同时实现多个接口;

2)一个类只能继承一个类,但是能实现多个接口

3)一个接口能继承另一个接口,这和类之间的继承比较相似。
展开阅读全文

没有更多推荐了,返回首页