当前位置: 首页 > 知识库问答 >
问题:

java - 如何理解面向对象好处:`多态允许我们在运行时更改对象的行为`?

顾涵衍
2024-08-12

多态的好处有如下的好处:

提高代码的灵活性:多态允许我们在运行时更改对象的行为。例如,我们可以将一个对象替换为另一个具有相同接口的对象,而不必更改调用代码。

请问下:
如何理解这句话呢:多态允许我们在运行时更改对象的行为

共有2个答案

经昱
2024-08-12

以下通过一个例子来解释:

// 定义一个接口
interface Animal {
    void makeSound();
}

// 实现接口的不同类
class Dog implements Animal {
    public void makeSound() {
        System.out.println("Woof!");
    }
}

class Cat implements Animal {
    public void makeSound() {
        System.out.println("Meow!");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal myAnimal;

        // 在运行时决定要创建的对象
        myAnimal = new Dog();
        myAnimal.makeSound();  // 输出: Woof!

        myAnimal = new Cat();
        myAnimal.makeSound();  // 输出: Meow!
    }
}

1、接口和实现:我们定义了一个 Animal 接口,所有实现该接口的类(如 Dog 和 Cat)都必须实现 makeSound() 方法。

2、多态行为:在 main 方法中,我们定义了一个 Animal 类型的变量 myAnimal。虽然这个变量的类型是 Animal,但它可以指向任何实现了 Animal 接口的对象(例如 Dog 或 Cat)。

3、运行时行为更改:在运行时,我们可以将 myAnimal 变量指向不同的对象(new Dog() 或 new Cat())。当我们调用 myAnimal.makeSound() 时,具体执行哪种行为(Woof! 或 Meow!)是由 myAnimal 在运行时所指向的对象决定的。

当 myAnimal 指向 Dog 对象时,调用 makeSound() 会输出 “Woof!”。
当 myAnimal 指向 Cat 对象时,调用 makeSound() 会输出 “Meow!”。

庞阳波
2024-08-12

在面向对象编程(OOP)中,多态(Polymorphism)是一种强大的特性,它允许我们以统一的方式处理不同类型的对象。当说“多态允许我们在运行时更改对象的行为”时,我们实际上是在描述多态如何使程序在运行时能够基于对象的实际类型(而非其声明的类型)来执行不同的操作。

这里有几个关键点来理解这句话:

  1. 接口或基类定义:首先,我们定义一个接口(在Java、C#等语言中)或基类(在C++、Python等语言中),它包含了一组方法,但不实现它们(在接口的情况下)或只提供默认实现(在基类的情况下)。这些方法定义了对象可以执行的操作。
  2. 子类实现:然后,我们创建继承自这个接口或基类的子类,并实现(或重写)这些方法。每个子类都可以以不同的方式实现这些方法,从而赋予对象不同的行为。
  3. 运行时绑定:在面向对象的语言中,当通过接口或基类的引用来调用方法时,实际执行哪个方法(即哪个类的实现)是在运行时确定的,这称为动态绑定或晚期绑定。这意味着,尽管引用可能是在编译时创建的,指向的是接口或基类类型,但调用哪个具体的方法取决于引用实际指向的对象类型。
  4. 更改行为:由于这种运行时绑定,我们可以在不修改调用代码的情况下,通过替换接口或基类引用所指向的对象来改变程序的行为。这就是“多态允许我们在运行时更改对象的行为”的含义。例如,我们可以有一个Shape接口,它有一个draw()方法。然后,我们可以创建CircleRectangle等类来实现这个接口。通过改变Shape引用所指向的对象(从CircleRectangle),我们可以在不修改调用draw()方法的代码的情况下,改变绘制行为。

这种能力极大地提高了代码的灵活性和可扩展性,因为它允许我们以更抽象的方式编写代码,将具体实现细节留给子类去处理。

 类似资料:
  • 我试图理解hibernate是如何工作的,即在类上放置@Entity是如何使它成为一个持久类的?即

  • 在下面的示例中,我希望组件在列表更新时重新渲染。但是即使连接传递了新状态,它也不会重新呈现组件。 我知道connect执行浅层比较,但不知道如何使其比较对象的值。我找不到任何启用选项的连接示例。 我已经了解了redux连接的组件如何知道何时重新渲染?还有一些,但也没用。 我试过了 只是试图让它重新渲染任何变化。这似乎也不起作用。 输出

  • 来自ISO/IEC 9899:201x第5.1.2.3节程序执行第4段: 关于volatile对象,这里允许的优化是什么?有人能给出一个可以优化掉的易失性访问的例子吗? 由于Volatile访问是一种可观察的行为(在第6段中描述),似乎没有任何优化可以针对Volatile进行,所以,我很想知道第4节中允许的优化是什么。

  • 问题内容: 我有很多自定义对象,需要对其执行独立(可并行化)的任务,包括修改对象参数。我试过同时使用Manager()。dict和’sharedmem’ory,但都没有用。例如: 打印出: 即对象没有被修改。 如何实现所需的行为? 问题答案: 问题在于,当将对象传递给工作进程时,它们会被泡菜包装,运送到另一个过程中,然后在其中解压缩并进行处理。您的对象没有像克隆的那样传递给其他过程。您不返回对象,

  • 问题内容: 我正在尝试遍历: …并提取中的每个元素。这是我的方法: 这里的问题是对的每次调用都会从中删除元素,从而修改其大小,从而导致以下错误: 那么…当元素动态变化时,我该如何遍历其中的元素呢? 问题答案: 其他人则提到了正确的解决方案,而没有实际阐明。所以这里是: 另外,如果您想安全地在assign函数中更改映射,则需要传入迭代器(只能使用remove函数,并且只能使用一次)或条目来更改值。

  • 我的课程注册项目应该有很多方法,比如(添加课程),(添加导师),等等(添加学生())就是其中之一,我想知道每次创建对象时如何更改对象的变量(std)我不知道每个对象如何都有相同的变量 那么,我想把变量改为std1、std2之类的任何建议 我想知道这是不是我做错了什么? 如果每个对象都用相同的变量声明,那么它会将每个创建的对象的数据克隆到新创建的对象? 谢谢你。