1.多态的概念

同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果,这就是多态性。

  • 多态是同一个行为具有多个不同表现形式或形态的能力。
  • 多态是方法的多态,不是属性的多态(多态与属性无关)
  • 父类引用指向子类对象后,用该父类引用调用子类重写的方法,此时多态就出现了。

简单来说:就是用基类的引用指向子类的对象。

1.1 多态的优势

  1. 消除类型之间的耦合关系
  2. 可替换性
  3. 可扩充性
  4. 接口性
  5. 灵活性
  6. 简化性

    1.2 多态存在要有3个必要条件

  • 继承
  • 方法重写
  • 父类引用指向子类对象
  1. Parent p = new Child();

当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,再去调用子类的同名方法。
多态的好处:可以使程序有良好的扩展,并可以对所有类的对象进行通用处理。

2.多态实现方式

接口实现、抽象类、继承父类进行方法重写、同一个类中进行方法重载。

2.1 抽象类和抽象方法

延伸拓展,如果在抽象类中增加方法,底层所有继承此类的子类都不需要修改,如果需调用,则直接调用父类方法即可。
抽象类是对整个类整体(属性、行为)进行抽象,但是接口却是对类局部(行为)进行抽象,所以抽象类一个是在项目开始就得确定好的公共类。

2.2 接口实现

辐射拓展,如果接口中新增加了方法,则需要修改所有实现此接口的实现方法。

  • 接口中的变量会被隐式地指定为 public static final 变量。
  • 接口中的方法都是抽象方法。
  • 一个类可继承多个接口。
  • 实现接口需实现接口中的所有方法。

    2.3 方法重写

    纵向拓展,子类可以重写父类的方法进行拓展

    2.4 方法重载

    横向拓展,方法的重写需参数不同、参数个数不同、返回值不同。

    3.抽象类与接口

    Ref: https://pdai.tech/md/java/basic/java-basic-lan-basic.html

    3.1 抽象类

    抽象类和抽象方法都使用 abstract 关键字进行声明。抽象类一般会包含抽象方法,抽象方法一定位于抽象类中。
    抽象类和普通类最大的区别是,抽象类不能被实例化,需要继承抽象类才能实例化其子类。 ```java public abstract class AbstractClassExample {

    protected int x; private int y;

    public abstract void func1();

    public void func2() {

    1. System.out.println("func2");

    } }

public class AbstractExtendClassExample extends AbstractClassExample { @Override public void func1() { System.out.println(“func1”); } }

// AbstractClassExample ac1 = new AbstractClassExample(); // ‘AbstractClassExample’ is abstract; cannot be instantiated AbstractClassExample ac2 = new AbstractExtendClassExample(); ac2.func1();

<a name="vXp9b"></a>
### 3.2 接口
接口是抽象类的延伸,在 Java 8 之前,它可以看成是一个完全抽象的类,也就是说它不能有任何的方法实现。<br />从 Java 8 开始,接口也可以拥有默认的方法实现,这是因为不支持默认方法的接口的维护成本太高了。在 Java 8 之前,如果一个接口想要添加新的方法,那么要修改所有实现了该接口的类。<br />接口的成员 (字段 + 方法) 默认都是 public 的,并且不允许定义为 private 或者 protected。<br />接口的字段默认都是 static 和 final 的。
```java
public interface InterfaceExample {
    void func1();

    default void func2(){
        System.out.println("func2");
    }

    int x = 123;
    // int y;               // Variable 'y' might not have been initialized
    public int z = 0;       // Modifier 'public' is redundant for interface fields
    // private int k = 0;   // Modifier 'private' not allowed here
    // protected int l = 0; // Modifier 'protected' not allowed here
    // private void fun3(); // Modifier 'private' not allowed here
}

public class InterfaceImplementExample implements InterfaceExample {
    @Override
    public void func1() {
        System.out.println("func1");
    }
}

// InterfaceExample ie1 = new InterfaceExample(); // 'InterfaceExample' is abstract; cannot be instantiated
InterfaceExample ie2 = new InterfaceImplementExample();
ie2.func1();
System.out.println(InterfaceExample.x);

3.3 比较

从设计层面上看:

  • 抽象类提供了一种 IS-A 关系,那么就必须满足里式替换原则,即子类对象必须能够替换掉所有父类对象(是不是)。而接口更像是一种 LIKE-A 关系,它只是提供一种方法实现契约(有没有),并不要求接口和实现接口的类具有 IS-A 关系。
  • 抽象类是对整个类整体(属性、行为)进行抽象,但是接口却是对类局部(行为)进行抽象,所以抽象类一个是在项目开始就得确定好的公共类。

从使用上来看:

  • 一个类可以实现多个接口,但是不能继承多个抽象类。
  • 接口的字段只能是 static 和 final 类型的,而抽象类的字段没有这种限制。
  • 接口的成员只能是 public 的,而抽象类的成员可以有多种访问权限。

    3.4 使用选择

    使用接口:

  • 需要让不相关的类都实现一个方法,例如不相关的类都可以实现 Compareable 接口中的 compareTo() 方法;

  • 需要使用多重继承;

使用抽象类:

  • 需要在几个相关的类中共享代码。
  • 需要能控制继承来的成员的访问权限,而不是都为 public。
  • 需要继承非静态和非常量字段。

在很多情况下,接口优先于抽象类,因为接口没有抽象类严格的类层次结构要求,可以灵活地为一个类添加行为。并且从 Java 8 开始,接口也可以有默认的方法实现,使得修改接口的成本也变的很低。