Java 多态

什么是多态

Java 的多态是面向对象编程的重要特性,它允许同一个类的不同对象实例对同一个方法做出不同的响应。简单说,多态就是同一种类型的对象,在不同的情况下会表现出不同的行为。

多态实例

现实中也有很多例子:

  • 在线聊天可以用 QQ,可以用微信,但是都是在线聊天。
  • 绿色出行可以坐公交,可以坐地铁,但是都是出行。

多态的实现方式

在 Java 中,多态可以由继承和接口两种机制实现,通过实现重写、指定的方法,Java 可以让程序在运行时动态地选择调用哪个方法,从而实现多态。这种特性可以使代码更加灵活,减少代码冗余,提高代码的可读性和可维护性。

继承实现多态

public class Animal{
  public void makeSound(){
    System.out.println("动物发出叫声");
  }
}
// 然后我们有一个猫类Cat,它继承了Animal类,但是它的叫声不同:
public class Cat extends Animal{
  @Override
  public void makeSound(){
    System.out.println("喵喵喵");
  }
}
// 同样,我们有一个狗类Dog,它也继承了Animal类,但是它的叫声不同:
public class Dog extends Animal{
  @Override
  public void makeSound(){
    System.out.println("汪汪汪");
  }
}

现在我们可以创建两个 Animal 对象,分别是猫和狗的实例。它们同样的方法,但是表现出的行为不同。

Animal cat = new Cat();
Animal dog = new Dog();
for (Animal animal : Arrays.asList(cat, dog)) {
    animal.makeSound();
}
// 喵喵喵
// 汪汪汪

这是一种 Java 多态的实现方式,不同的子类继承了同一个父类,重写了同一个方法,表现出的行为不同。这样的设计,使得代码更加灵活,具有更好的可扩展性和可维护性。

接口实现多态

实现接口和继承类实现多态大致相同。

public interface Animal{
  void makeSound();
}
// 然后我们有一个猫类Cat,和一个狗类Dog,Animal,并且都有自己特定的叫声:
public class Cat implements Animal{
  @Override
  public void makeSound(){
    System.out.println("喵喵喵");
  }
}

public class Dog implements Animal{
  @Override
  public void makeSound(){
    System.out.println("汪汪汪");
  }
}

同样的测试:

Animal cat = new Cat();
Animal dog = new Dog();
for (Animal animal : Arrays.asList(cat, dog)) {
    animal.makeSound();
}
// 喵喵喵
// 汪汪汪

多态的特点

多态的一大特点就是运行时才决定调用的是哪个方法,上面的例子中,都是对一个 Animal 对象调用,然后表现出来的行为不同。完全可以以 Animal 类型作为方法的入参,这样这个方法就不用关心传入的是 Cat 还是 Dog,调用 makeSound 方法的行为会在运行时动态决定。

/**
 * @author www.wdbyte.com
 * @date 2023/04/18
 */
public class Test2 {
    public static void main(String[] args) {
        Animal cat = new Cat();
        Animal dog = new Dog();
        makeSound(cat); // 喵喵喵
        makeSound(dog); // 汪汪汪
    }

    public static void makeSound(Animal animal) {
        animal.makeSound();
    }
}

多态的优点

Java中的多态优点如下:

  1. 提高代码的可扩展性和可维护性:多态可以让程序员在不修改已有代码的情况下扩展系统的功能,从而降低了系统的维护成本。
  2. 简化代码的逻辑:多态可以让程序员只需要关注对象的行为,而不必关心具体的对象类型。
  3. 提高代码的重用性:通过继承和接口的方式,可以将代码的相同部分抽取出来,减少了代码冗余,提高了代码的重用性。
  4. 提高代码的灵活性:多态可以让程序员在运行时动态地选择具体的实现方式,从而提高了代码的灵活性和可配置性。
  5. 提高代码的可读性和可理解性:多态可以让代码更加直观和易于理解,提高了代码的可读性和可理解性。

为什么要用多态

上面的例子已经举例了多态的用法,多态的优点也就是使用多态的原因。下面再举一个例子进行说明。

假如你要开发一个功能,允许用户可以向阿里云 OSS 或者腾讯云 OSS 上传文件内容。不使用多态,你可能需要编写两个独立的阿里云 OSS 操作类,腾讯云 OSS 操作类,那么使用多态如何实现呢?

  1. 定义一个 Oss 操作接口。
/**
 * @author www.wdbyte.com
 */
public interface Oss {
    
    /**
     * 文件上传
     * @param content
     */
    void upload(String content);
}
  1. 定义阿里云 OSS 和腾讯云 OSS 类。

    public class AliyunOss implements Oss {
        @Override
        public void upload(String content) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("文件已经上传到阿里云 OSS,内容:" + content);
        }
    }
    
    public class TencentOss implements Oss {
        @Override
        public void upload(String content) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("文件已经上传到腾讯云 OSS,内容:" + content);
        }
    }
    
  2. 定义 Oss 操作工具类,可以统计上传耗时。

    public class OssUtil {
        /**
         * OSS 上传工具类
         *
         * @param oss
         * @param content
         */
        public static void upload(Oss oss, String content) {
            long start = System.currentTimeMillis();
            oss.upload(content);
            long end = System.currentTimeMillis();
            System.out.println("上传耗时:" + (end - start) + "ms");
        }
    }
    
  3. 测试阿里云 OSS 和腾讯云 OSS 内容上传。

    public static void main(String[] args) {
        AliyunOss aliyunOss = new AliyunOss();
        TencentOss tencentOss = new TencentOss();
        upload(aliyunOss, "Hello aliyun");
        System.out.println("------------");
        upload(tencentOss, "Hello tencent");
    }
    // 文件已经上传到阿里云 OSS,内容:Hello aliyun
    // 上传耗时:12ms
    // ------------
    // 文件已经上传到腾讯云 OSS,内容:Hello tencent
    // 上传耗时:101ms
    

这里的 OssUtil 是完全独立的,入参的类型是 Oss ,不管以后增加了华为云 Oss 还是谷歌云 Oss,都只需要定义相应的 Oss 类即可,提高了代码的可扩展性,可复用性。

一如既往,文章中代码存放在 Github.com/niumoo/javaNotes.