假设我有两个类:Animal 和 Dog。狗是动物的子类。我执行以下代码:
Animal a = new Dog();
现在我可以通过 a 变量调用 Dog 类的方法。
但我的问题是:如果我可以通过 Dog 对象(继承)调用 Animal 的所有方法,那么我为什么要使用多态性原理?我可以声明:
Dog d = new Dog();
有了这个声明,就可以使用 Animal 的所有方法和 Dog 方法。那么为什么要使用多态呢?非常感谢您的回答。
假设我有两个类:Animal 和 Dog。狗是动物的子类。我执行以下代码:
Animal a = new Dog();
现在我可以通过 a 变量调用 Dog 类的方法。
但我的问题是:如果我可以通过 Dog 对象(继承)调用 Animal 的所有方法,那么我为什么要使用多态性原理?我可以声明:
Dog d = new Dog();
有了这个声明,就可以使用 Animal 的所有方法和 Dog 方法。那么为什么要使用多态呢?非常感谢您的回答。
在 Java 中,多态和继承的概念是“焊接在一起的”;一般来说,它不必是这样的:
有些语言将继承与多态性分离:
virtual
)回到 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 上有一个很好的答案来解释它。
您可以拥有Animal
该类的其他实现,例如Cat
. 然后你可以说
Animal a = new Dog();
Animal b = new Cat();
你可以调用Animal
类的方法而不用关心它到底是哪个实现,多态会调用正确的方法。例如
a.speak(); // "Woof"
b.speak(); // "Meow"
真的,这不是“多态与继承”,而是“使用继承的多态”。
多态性允许您编写适用于任何的方法Animal
:
public void pet(Animal animal) {
...
}
此方法将接受Dog
,Cat
等,包括Animal
尚未编写的子类。
如果采用该方法Dog
,它将不适用于Cat
等。
如果你确定它永远是一只狗,那就没有理由了。你也可以使用Dog d = new Dog(); 正如你所描述的。但是,假设您使用了方法而不是构造函数。该方法返回了一个动物,你不知道你会得到哪个动物实现。您仍然可以对动物使用相同的方法(即使它是狗、象猫等)。
出于可扩展性的目的,继承简化了事情。当你想创建一个也共享一些动物方法的大象或猫时,你可以通过将动物作为超类来轻松获得这些方法。
通常你问的问题更类似于继承与组合:)更多“现实生活”的例子说明为什么使用多态是好的例如策略设计模式的使用。您可以有许多 TaxPolicy 实现:UsaTaxPolicy、CanadaTaxPolicy、EuTaxPolicy 等。如果您有方法 calculateFinalPrice,它还必须计算税款,那么您注入正确的实现并执行良好的计算,无论您是否通过美国、加拿大或欧盟实施。
继承是动态多态性。我的意思是当你删除继承时,你不能再覆盖了。