多态性vs覆盖vs重载
就Java而言,当有人问:
what is polymorphism?
重载或者重载是可以接受的答案吗?
我认为还有更多。
如果我们有一个抽象基类,它定义了一个没有实现的方法,并且我们在子类中定义了该方法,那该方法是否仍会覆盖?
我认为过载不是肯定的正确答案。
解决方案
重载一词是指具有相同名称的某些事物的多个版本,通常是具有不同参数列表的方法
public int DoSomething(int objectId) { ... } public int DoSomething(string objectName) { ... }
因此,这些功能可能会执行相同的操作,但是我们可以选择使用ID或者名称来调用它。与继承,抽象类等无关。
正如我们在问题中所描述的那样,重载通常是指多态性
我们是正确的,过载不是答案。
两者都不是最重要的。覆盖是获得多态的手段。多态是对象根据其类型改变行为的能力。当显示多态性的对象的调用者不知道该对象是哪种特定类型时,最好地证明这一点。
重载是当我们定义两个具有相同名称但参数不同的方法时
覆盖是通过子类中具有相同名称的函数更改基类的行为的地方。
因此,多态与覆盖有关,但实际上与过载无关。
但是,如果有人对"什么是多态性"这个问题给了我一个简单的"覆盖"答案。我要求进一步解释。
多态是对象以多种形式出现的能力。这涉及使用继承和虚拟函数来构建可以互换的对象系列。基类包含虚拟函数的原型,可能未实现或者根据应用程序的指示具有默认实现,并且各个派生类各自以不同方式实现它们以影响不同的行为。
经典的例子是,猫狗是动物,动物具有makeNoise方法。我可以遍历一系列对它们调用makeNoise的动物,并期望它们会在那里执行相应的实现。
调用代码不必知道它们是什么特定动物。
那就是我认为的多态性。
这是伪C#/ Java中多态的示例:
class Animal { abstract string MakeNoise (); } class Cat : Animal { string MakeNoise () { return "Meow"; } } class Dog : Animal { string MakeNoise () { return "Bark"; } } Main () { Animal animal = Zoo.GetAnimal (); Console.WriteLine (animal.MakeNoise ()); }
Main函数不知道动物的类型,而是取决于MakeNoise()方法的特定实现的行为。
编辑:看起来布莱恩击败我一拳。有趣的是,我们使用了相同的示例。但是上面的代码应该有助于阐明概念。
覆盖和重载均用于实现多态。
你可以在一个类中有一个方法
被一个或者多个
更多子类。该方法确实
不同的东西取决于
类用于实例化对象。
abstract class Beverage { boolean isAcceptableTemperature(); } class Coffee extends Beverage { boolean isAcceptableTemperature() { return temperature > 70; } } class Wine extends Beverage { boolean isAcceptableTemperature() { return temperature < 10; } }
我们也可以使用一种方法
重载了两组或者更多组参数。该方法确实
基于不同的东西
传递的参数类型。
class Server { public void pour (Coffee liquid) { new Cup().fillToTopWith(liquid); } public void pour (Wine liquid) { new WineGlass().fillHalfwayWith(liquid); } public void pour (Lemonade liquid, boolean ice) { Glass glass = new Glass(); if (ice) { glass.fillToTopWith(new Ice()); } glass.fillToTopWith(liquid); } }
两者都不:
重载是当我们具有相同的函数名称且采用不同的参数时。
覆盖是指子类用其父类的方法替换其父类的方法时(这本身并不构成多态性)。
多态性是后期结合,例如。基本类(父类)方法被调用,但是直到运行时应用程序知道实际对象是什么,它才可能是其方法不同的子类。这是因为可以在定义基类的地方使用任何子类。
在Java中,我们可以通过collections库看到很多多态性:
int countStuff(List stuff) { return stuff.size(); }
List是基类,如果我们要计算链接列表,向量,数组或者自定义列表实现,则编译器不知道,只要它的作用类似于List:
List myStuff = new MyTotallyAwesomeList(); int result = countStuff(myStuff);
如果我们超载,我们将:
int countStuff(LinkedList stuff) {...} int countStuff(ArrayList stuff) {...} int countStuff(MyTotallyAwesomeList stuff) {...} etc...
编译器将选择正确版本的countStuff()来匹配参数。
多态性与语言使用单一接口统一对待不同对象的能力有关。因为它与覆盖相关,所以接口(或者基类)是多态的,实现者是覆盖的对象(同一枚奖牌的两个面)
无论如何,可以使用其他语言(例如c ++)更好地解释这两个术语之间的区别:如果基本函数是虚拟的,则c ++中的多态对象将作为java的对应对象,但是如果方法不是虚拟的,则代码跳转是静态解决的,并且在运行时不检查真实类型,因此,多态性包括对象根据其访问接口的不同而具有不同行为的能力;让我用伪代码举例说明:
class animal { public void makeRumor(){ print("thump"); } } class dog extends animal { public void makeRumor(){ print("woff"); } } animal a = new dog(); dog b = new dog(); a.makeRumor() -> prints thump b.makeRumor() -> prints woff
(假设makeRumor不是虚拟的)
Java并没有真正提供这种级别的多态性(也称为对象切片)。
动物a = new dog();
狗b =新的dog();
a.makeRumor() -> prints thump b.makeRumor() -> prints woff
在这两种情况下,它只会打印woff。
因为a和b指的是狗类
多态性是类实例的行为,就好像它是其继承树中的另一个类的实例一样,通常是其祖先类之一。例如,在Java中,所有类都从Object继承。因此,我们可以创建Object类型的变量,并为其分配任何类的实例。
覆盖是一种函数类型,它发生在从另一个类继承的类中。覆盖函数"替换"从基类继承的函数,但这样做的方式是,即使通过多态性假装其类的实例是其他类型,也可以调用该函数。参考前面的示例,我们可以定义自己的类并覆盖toString()函数。因为此函数是从Object继承的,所以如果将此类的实例复制到Object-type变量中,则该函数仍然可用。通常,如果在假装为Object的类上调用toString(),则实际上将触发的toString版本是在Object本身上定义的版本。但是,由于该函数是重写,因此即使类实例的真实类型隐藏在多态性之后,也将使用类中的toString()定义。
重载是定义多个具有相同名称但具有不同参数的方法的操作。它与覆盖或者多态无关。
具体说重载或者覆盖并不能提供完整的图像。多态只是对象根据其类型专门化其行为的能力。
我不同意这里的一些答案,因为在同名方法可以表现不同的情况下,重载是多态(参数多态)的一种形式,它给出不同的参数类型。一个很好的例子是运算符重载。我们可以定义" +"以接受不同类型的参数(例如字符串或者整数),并且基于这些类型," +"的行为将有所不同。
多态性还包括继承和覆盖方法,尽管它们在基本类型中可以是抽象的也可以是虚拟的。在基于继承的多态性方面,Java仅支持单类继承,将其多态行为限制为单基类型链的多态行为。 Java确实支持实现多个接口,这是多态行为的另一种形式。
表达多态性的最清晰方法是通过抽象基类(或者接口)
public abstract class Human{ ... public abstract void goPee(); }
此类是抽象的,因为无法为人类定义goPee()
方法。只有男性和女性子类别才可以定义。同样,人类是一个抽象的概念。我们不能创造既不是男性也不是女性的人类。它必须是一个或者另一个。
因此,我们通过使用抽象类来推迟实现。
public class Male extends Human{ ... @Override public void goPee(){ System.out.println("Stand Up"); } }
和
public class Female extends Human{ ... @Override public void goPee(){ System.out.println("Sit Down"); } }
现在我们可以告诉充满人类的整个房间撒尿。
public static void main(String[] args){ ArrayList<Human> group = new ArrayList<Human>(); group.add(new Male()); group.add(new Female()); // ... add more... // tell the class to take a pee break for (Human person : group) person.goPee(); }
运行此将产生:
Stand Up Sit Down ...
多态仅表示"许多形式"。
它不需要继承就可以实现...因为根本不是继承的接口实现满足了多态需求。可以说,接口实现服务于多态需求而不是继承。
例如,我们会创建一个超类来描述所有可以飞行的东西吗?我不认为。最好为我们创建一个描述航班的界面,然后将其保留。
因此,由于接口描述了行为,而方法名称描述了行为(对程序员而言),因此将方法重载视为一种较小的多态形式并不是一件容易的事。