目 录CONTENT

文章目录

面向对象-多态

~梓
2024-12-24 / 0 评论 / 0 点赞 / 50 阅读 / 0 字
温馨提示:
本文最后更新于2024-12-24,若内容或图片失效,请留言反馈。 部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

多态

一、多态的概念

多态是面向对象编程中的一个重要特性,它允许不同类的对象对同一消息(也就是方法调用)做出不同的响应,简单来说就是"多种形态"。在 Java 等面向对象语言中,多态主要通过继承、接口实现以及方法重写(覆盖)来体现。

多态是指同一行为作用于不同对象时,可以表现出多种不同的形式和结果来。例如,子类继承父类子类继承父类并覆盖其方法后,用父类引用指向子类对象并调用该方法时,实际执行的是子类的方法。

这种根据对象实际类型而非声明类型来确定执行方法的行为,就是多态性的体现。多态主要通过继承和接口实现,允许同一接口有多种不同的实现方式。

二、多态的分类

  • 编译时多态,又称静态绑定,是指编译器在编译时通过检查引用类型的方法是否存在,来定位到相应的类及其方法,而不检查实际对象是否支持该方法。编译时多态主要体现在方法重载上,即根据参数类型、数量和顺序,在编译时确定要执行的方法。
  • 运行时多态,又称动态绑定,是指程序在运行时根据对象的实际类型来确定调用哪个方法,而不是在编译时确定。这意味着方法的具体实现取决于对象的实际类型,而非其声明类型。父类引用可以指向不同的子类对象,使得相同方法调用产生不同的行为结果。通过运行时确定具体执行的方法,代码具有更好的扩展性和可维护性。

三、多态三个必要条件:

严格来说,多态需要具备以下三个条件。

  1. 继承:子类继承父类或实现接口。
  2. 重写:子类覆盖父类的方法。
  3. 父类声明子类:使用父类引用来声明子类对象。

四、多态的好处,为什么要用多态?

在面向对象设计中,"开闭原则"是非常重要的一条。即系统中的类应该对扩展开放,而对修改关闭。这样的代码更可维护和可扩展,同时更加简洁与清晰。

五、案例

使用工厂方法模式设计一个程序用来读取各种不同类型的图片格式,针对每一种图片格式都设计一个图片读取器(ImageReader),例如GIF图片读取器(GifReader)用于读取GIF格式的图片、JPG图片读取器(JpgReader)用于读取JPG格式的图片,在设计时,要充分考虑系统的灵活性和可扩展性。

imageReader.png

代码如下

ImageReaderFactory接口

public interface ImageReaderFactory {

	public ImageReader createImage();

}

ImageReader接口

public interface ImageReader {

	public void readImage();

}

JpgReaderFactory类

public class JpgReaderFactory implements ImageReaderFactory {

	public JpgReaderFactory(){

	}

	public ImageReader createImage(){
		return new JpgReader();
	}

}

JpgReader类

public class JpgReader implements ImageReader {

	public JpgReader(){

	}

	public void readImage(){
		System.out.println("读取Jpg图片");
	}

}

GifReaderFactory类

public class GifReaderFactory implements ImageReaderFactory {

	public GifReaderFactory(){

	}

	public ImageReader createImage(){
		return new GifReader();
	}

}

GifReader类

public class GifReader implements ImageReader {

	public GifReader(){

	}

	public void readImage(){
		System.out.println("读取Gif图片");
	}

}

测试类Client

public class Client {
    public static void main(String[] args) {
        ImageReaderFactory imageReaderFactory = new GifReaderFactory();
        ImageReader imageReader = imageReaderFactory.createImage();
        imageReader.readImage();
        jpgMethod();
    }

    public static void jpgMethod() {
        ImageReaderFactory imageReaderFactory = new JpgReaderFactory();
        ImageReader imageReader = imageReaderFactory.createImage();
        imageReader.readImage();
    }
}

六、多态在案例中的体现

  • 基于接口实现的多态
    • 在提供的代码里,有 ImageReaderFactory 接口和 ImageReader 接口。JpgReaderFactory 类实现了 ImageReaderFactory 接口,JpgReader 类实现了 ImageReader 接口。
    • 对于 ImageReaderFactory 接口,当执行 ImageReaderFactory imageReaderFactory = new JpgReaderFactory(); 这行代码时,就体现了多态性。这里定义了一个 ImageReaderFactory 接口类型的变量 imageReaderFactory,但实际将 JpgReaderFactory(一个具体实现了该接口的类)的实例赋值给了它。这意味着,从代码层面看,imageReaderFactory 变量可以代表任何实现了 ImageReaderFactory 接口的类的实例,后续代码只通过这个接口类型的变量来操作,而不用关心具体是哪个实现类的对象,只要符合接口规范就行。
    • 同理,对于 ImageReader 接口,ImageReader imageReader = imageReaderFactory.createImage(); 这行代码中,imageReader 变量是 ImageReader 接口类型,它接收了 JpgReader(实现该接口的具体类)的实例,同样展示了多态,即不管是哪种实现 ImageReader 接口的类的对象,都可以通过这个接口类型变量统一调用 readImage 方法。
  • 方法重写(覆盖)与多态的关联

    • JpgReader 类中重写了 ImageReader 接口里定义的 readImage 方法,重写时遵循了方法签名(方法名、参数列表、返回类型等要和接口中定义的一致,对于接口中定义返回类型为接口类型的情况,实现类重写方法返回的具体实现类要满足接口类型要求,比如这里 ImageReader 接口要求返回类型为 ImageReaderJpgReader 返回自身实例满足要求)相同的规则。
    • 当通过 imageReader.readImage(); 调用这个方法时(此时 imageReader 实际指向的是 JpgReader 的实例),会执行 JpgReader 类里重写后的 readImage 方法逻辑(也就是输出 "读取Jpg图片"),而不是 ImageReader 接口中抽象定义的那个未具体实现的方法逻辑。如果后续有其他类(比如 PngReader 类假设实现了 ImageReader 接口并也重写了 readImage 方法),同样通过 ImageReader 接口类型变量调用 readImage 方法时,就会执行对应类里重写后的逻辑,这就是不同对象(不同实现类的实例)对同一方法调用(readImage 方法调用)做出不同响应,充分体现了多态性。
  1. 类型声明与实际对象类型差异
    • ImageReaderFactory imageReaderFactory = new JpgReaderFactory();这行代码中,变量 imageReaderFactory的类型被声明为 ImageReaderFactory接口类型。这是一种抽象的类型定义,表示这个变量应该遵循 ImageReaderFactory接口所规定的行为规范。
    • 然而,实际赋值给这个变量的是 JpgReaderFactory类的实例。JpgReaderFactory是一个具体的类,它实现了 ImageReaderFactory接口,这就产生了类型上的差异。这种差异是多态的一个重要体现,因为代码是基于接口(抽象类型)来操作的,但可以使用不同的具体实现类的对象来满足这个接口的要求。
  2. 方法调用的灵活性和多样性
    • 当通过 imageReaderFactory变量调用方法时,例如 imageReaderFactory.createImage();,由于 imageReaderFactory的类型是 ImageReaderFactory接口,编译器只知道它可以调用 ImageReaderFactory接口中定义的方法(在这里是 createImage方法)。
    • 但是,实际执行的方法是由赋值给 imageReaderFactory的具体对象(也就是 JpgReaderFactory的实例)来决定的。如果将来有另一个类(比如 PngReaderFactory)也实现了 ImageReaderFactory接口,并且在 jpgMethod函数中,imageReaderFactory被赋值为 PngReaderFactory的实例,那么同样的 createImage方法调用会执行 PngReaderFactory类中实现的 createImage方法,产生不同的结果。
    • 这就体现了多态性,即相同的方法调用(createImage)在不同的具体对象(JpgReaderFactoryPngReaderFactory等符合接口的实例)下可以有不同的行为,使得代码能够根据实际赋值的对象来灵活地执行相应的操作。
0

评论区