21

假设我有两个类:Animal 和 Dog。狗是动物的子类。我执行以下代码:

Animal a = new Dog();

现在我可以通过 a 变量调用 Dog 类的方法。

但我的问题是:如果我可以通过 Dog 对象(继承)调用 Animal 的所有方法,那么我为什么要使用多态性原理?我可以声明:

Dog d = new Dog();

有了这个声明,就可以使用 Animal 的所有方法和 Dog 方法。那么为什么要使用多态呢?非常感谢您的回答。

4

6 回答 6

25

在 Java 中,多态和继承的概念是“焊接在一起的”;一般来说,它不必是这样的:

  • 多态性使您可以在不知道类的确切类型的情况下调用类的方法
  • 继承允许派生类共享其基类的接口和代码

有些语言将继承与多态性分离:

  • 在 C++ 中,您可以在不产生多态行为的情况下继承一个类(即不要用 标记基类中的函数virtual
  • 在 Objective C 中,您可以在不相关的类上实现方法,并从只知道方法签名的地方调用它。

回到 Java,使用多态性的原因是将你的代码与其对应方的实现细节解耦:例如,如果你可以编写一个Feed(Animal animal)适用于各种动物的方法,那么当你添加更多的子类或实现Animal。这与一种Feed(Dog dog)与狗紧密耦合的方法形成对比。

至于

Dog d = new Dog();

声明去,如果你知道你的方法的其余部分专门处理狗,没有一般的理由来避免这种情况。但是,在许多情况下,后者并非如此:例如,您的类或您的方法通常对确切的实现不敏感,例如

List<Integer> numbers = new ArrayList<Integer>();

在这种情况下,您可以替换new ArrayList<Integer>()new LinkedList<Integer>(),并且知道您的代码将要编译。相反,如果您的numbers列表被声明为ArrayList<Integer> numbers,则这种切换可能不是确定性的。

这称为“对接口编程”。Stack Overflow 上有一个很好的答案来解释它。

于 2013-04-05T16:39:56.250 回答
5

您可以拥有Animal该类的其他实现,例如Cat. 然后你可以说

Animal a = new Dog();
Animal b = new Cat();

你可以调用Animal类的方法而不用关心它到底是哪个实现,多态会调用正确的方法。例如

a.speak();  // "Woof"

b.speak();  // "Meow"

真的,这不是“多态与继承”,而是“使用继承的多态”。

于 2013-04-05T16:33:05.377 回答
4

多态性允许您编写适用于任何的方法Animal

public void pet(Animal animal) {
   ...
}

此方法将接受Dog,Cat等,包括Animal尚未编写的子类。

如果采用该方法Dog,它将不适用于Cat等。

于 2013-04-05T16:33:13.017 回答
1

如果你确定它永远是一只狗,那就没有理由了。你也可以使用Dog d = new Dog(); 正如你所描述的。但是,假设您使用了方法而不是构造函数。该方法返回了一个动物,你不知道你会得到哪个动物实现。您仍然可以对动物使用相同的方法(即使它是狗、象猫等)。

出于可扩展性的目的,继承简化了事情。当你想创建一个也共享一些动物方法的大象或猫时,你可以通过将动物作为超类来轻松获得这些方法。

于 2013-04-05T16:40:09.333 回答
0

通常你问的问题更类似于继承与组合:)更多“现实生活”的例子说明为什么使用多态是好的例如策略设计模式的使用。您可以有许多 TaxPolicy 实现:UsaTaxPolicy、CanadaTaxPolicy、EuTaxPolicy 等。如果您有方法 calculateFinalPrice,它还必须计算税款,那么您注入正确的实现并执行良好的计算,无论您是否通过美国、加拿大或欧盟实施。

于 2014-01-11T20:00:30.327 回答
0

继承是动态多态性。我的意思是当你删除继承时,你不能再覆盖了。

于 2017-12-07T15:54:49.783 回答