什么是多态,它是什么,以及它是如何使用的?

Unk*_*ech 541 oop polymorphism computer-science

我正在观看Google Tech Talks视频,他们经常提到多态性.

什么是多态,它是什么,以及它是如何使用的?

pax*_*blo 527

如果你考虑这个术语的希腊词根,它应该变得明显.

  • Poly = many:polygon = many-sided,polystyrene = many styrenes (a),polyglot = many languages,依此类推.
  • 形态=变化或形式:形态=研究生物形态,Morpheus =希腊梦之神能够采取任何形式.

因此,多态性是(在编程中)为不同的底层形式(数据类型)呈现相同的接口的能力.

例如,在许多语言中,整数和浮点数是隐式多态的,因为您可以添加,减去,乘法等,而不管类型是否不同.它们很少被视为通常术语中的对象.

但是,以同样的方式,类似BigDecimal或者RationalImaginary可以提供这些操作,即使它们在不同的数据类型上运行.

经典的例子是Shape类和可以从它继承的所有类(正方形,圆形,十二面体,不规则多边形,splat等).

使用多态,这些类中的每一个都将具有不同的底层数据.点形状只需要两个坐标(假设它当然在二维空间中).圆圈需要一个圆心和半径.正方形或矩形需要两个坐标用于左上角和右下角以及(可能)旋转.不规则多边形需要一系列线条.

通过使类负责其代码及其数据,您可以实现多态.在这个例子中,每个类都有自己的Draw()功能,客户端代码可以简单地执行:

shape.Draw()
Run Code Online (Sandbox Code Playgroud)

获得任何形状的正确行为.

这与代码与数据分离的旧方法形成对比,并且您将拥有诸如drawSquare()和之类的函数drawCircle().

面向对象,多态和继承都是密切相关的概念,它们对于了解至关重要.在我漫长的职业生涯中,有很多"银子弹"基本上刚刚失败,但OO范例已经证明是一个很好的.学习它,理解它,喜欢它 - 你会很高兴你做到了:-)


(a)我最初把它写成一个笑话,但事实证明它是正确的,因此,并不那么有趣.事实上苯乙烯恰好是由碳和氢制成的,而聚苯乙烯是由那些组成的.C8H8(C8H8)n

也许我应该已经说过,息肉很多都是这封信,p尽管现在我已经不得不解释这个笑话了,即使这看起来也不好笑.

有时,你应该在你落后时退出:-)

  • 希腊语,而非拉丁语:)('y'和'ph'是赠品).在希腊语中,'morph-'只是''shape'或'form' - 'morph'的'*change*shape'的英文含义是后来的发展 (46认同)
  • 多态性与OOP无关,但OOP与多态性有关,因为它本身就支持它(假设它是一种不错的OOP语言).查看FP以获取其他多态性示例. (13认同)
  • 这两条线为我做了诀窍:`Poly = many和Morph = change或form` (9认同)
  • 息肉是polypo(u)的缩写.pous在希腊脚下.;-) (2认同)
  • @Shaun,我认为您可能在过于字面化/狭隘的意义上使用“接口”一词 - 我的意思是它是一个英语术语,而不是特定于某些任意计算机语言的定义。它并不意味着具有完全相同参数的完全相同的函数,它只是一种以相同的方式影响“对象”的方式,而不管它们的底层具体类型如何。这可以包括使用不同参数类型的方法重载以及更纯粹的多态形式。 (2认同)
  • 关于您的编辑:“解释一个笑话就像解剖一只青蛙。你更了解它,但青蛙在这个过程中死去了。” - EB 白 (2认同)

Ant*_*bbs 238

多态性是指您可以将对象视为某种东西的通用版本,但是当您访问它时,代码会确定它的确切类型并调用相关代码.

这是C#中的一个例子.在控制台应用程序中创建四个类:

public abstract class Vehicle
{
    public abstract int Wheels;
}

public class Bicycle : Vehicle
{
    public override int Wheels()
    {
        return 2;
    }
}

public class Car : Vehicle
{
    public override int Wheels()
    {
        return 4;
    }
}

public class Truck : Vehicle
{
    public override int Wheels()
    {
        return 18;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在在控制台应用程序的模块的Main()中创建以下内容:

public void Main()
{
    List<Vehicle> vehicles = new List<Vehicle>();

    vehicles.Add(new Bicycle());
    vehicles.Add(new Car());
    vehicles.Add(new Truck());

    foreach (Vehicle v in vehicles)
    {
        Console.WriteLine(
            string.Format("A {0} has {1} wheels.",
                v.GetType().Name, v.Wheels));
    }
}
Run Code Online (Sandbox Code Playgroud)

在这个例子中,我们创建了一个基类Vehicle的列表,它不知道每个子类有多少个轮子,但是知道每个子类负责知道它有多少个轮子.

然后我们将自行车,汽车和卡车添加到列表中.

接下来,我们可以循环遍历列表中的每个Vehicle,并对它们进行相同的处理,但是当我们访问每个Vehicle'Wheels'属性时,Vehicle类将该代码的执行委托给相关的子类.

该代码被称为多态的,因为执行的确切代码由运行时引用的子类确定.

我希望这对你有所帮助.

  • 我认为这是一个非常好的例子,可以清楚地显示父界面,并且直到对象被实例化才需要具体版本,即车辆与汽车 (6认同)

Aja*_*tel 192

理解和应用PHP中的多态性,感谢Steve Guidetti.

多态性是一个非常简单的概念.

多态性描述了面向对象编程中的模式,其中类在共享公共接口时具有不同的功能.

多态的优点在于,使用不同类的代码不需要知道它正在使用哪个类,因为它们都以相同的方式使用.多态性的现实世界类比是一个按钮.每个人都知道如何使用按钮:你只需对它施加压力.然而,按钮"做什么"取决于它所连接的内容以及使用它的上下文 - 但结果不会影响它的使用方式.如果您的老板告诉您按下按钮,您已经拥有执行任务所需的所有信息.

在编程领域,多态性用于使应用程序更加模块化和可扩展.您可以根据需要创建可互换的对象,而不是描述不同操作过程的混乱条件语句.这是多态性的基本目标.

  • 是不是与抽象概念更相关的按钮类比? (10认同)
  • @Mantriur:这确实是抄袭的,而且我们有相反的规则:http://stackoverflow.com/help/referencing但是现在考虑到它的分数以及旧帖子在答案删除时免于代表丢失的事实,我不是确定如果现在完全删除它会改善任何事情.下一个最好的选择是仅代表用户编辑归属,即使我坚信用户有责任在他们自己的答案中引用来源. (8认同)
  • 原始资料来源:http://code.tutsplus.com/tutorials/understanding-and-applying-polymorphism-in-php--net-14362 (6认同)

小智 58

如果有人对这些人说过CUT

  1. 外科医生
  2. 发型师
  3. 演员

会发生什么?

  • 外科医生会开始做切口.
  • 发型师会开始剪掉某人的头发.
  • 演员将突然停止在当前场景中行动,等待导演指导.

所以上面的表示显示了OOP中的多态(同名,不同行为)是什么.

如果你要去面试并且面试官要求你告诉/展示我们所在的同一个房间的多态性的实例,比如说 -

答案 - 门/窗

想知道怎么样?

通过门/窗 - 一个人可以来,空气可以来,光可以来,雨可以来,等等.

为了更好地理解它,并以简单的方式使用上面的例子..如果你需要参考代码,请按照上面的答案.

  • 我认为这不是一个很好的例子,因为它可能会使没有经验的人认为如果两个类都具有`.foo()`方法,那么它们应该共享一个公共接口。但是,这不是真的,并且会导致错误的抽象。接口应定义要播放的“角色”,该角色可能具有许多不同的实现,但所有实现都从同一组输入中拉出并从同一组输出中返回。外科医生,造型师或演员在x.cut(...)中输入的内容都不相同,输出也不相同。 (5认同)

BKS*_*eon 33

简单的类比解释

美国总统采用多态性.怎么样?好吧,他有很多顾问:

  1. 军事顾问
  2. 法律顾问
  3. 核物理学家(顾问)
  4. 医疗顾问
  5. 等等

每个人都应该对一件事负责:例如:

总统不是锌涂层或量子物理专家.他不知道很多事情 - 但他只知道一件事:如何管理这个国家.

它与代码有点相同:关注点和责任应该与相关的类/人分开.否则你会让总统知道世界上的一切 - 整个维基百科.想象一下,将整个维基百科放在一个代码类中:维护它将是一场噩梦.

为什么总统要知道所有这些具体的事情是个坏主意?

如果总统要专门告诉人们该做什么,那就意味着总统需要知道该做什么.如果总统需要自己了解具体事情,那就意味着当你需要做出改变时,你需要在两个地方做到,而不仅仅是一个.

例如,如果环保署改变了污染法律,那么当发生这种情况时:你必须改变EPA班级总统班级.在两个地方而不是一个地方更改代码可能很危险 - 因为维护起来要困难得多.

有更好的方法吗?

有一种更好的方法:总统不需要知道任何事情的具体细节 - 他可以要求那些专门负责这些事情的人提供最好的建议.

他可以使用多态方法来运行这个国家.

示例 - 使用多态方法:

总统所做的就是要求人们为他提供建议 - 而这正是他在现实生活中所做的事情 - 这就是一位优秀的总统应该做的事情.他的顾问都有不同的反应,但他们都知道总统的意思:建议().他有数百人涌入他的办公室.实际上他们是谁并不重要.所有总统都知道,当他要求他们"建议"时,他们知道如何做出相应的回应:

public class MisterPresident
{
    public void RunTheCountry()
    {
        // assume the Petraeus and Condi classes etc are instantiated.
        petraeus.Advise(); // # Petraeus says send 100,000 troops to Fallujah
        condolezza.Advise(); // # she says negotiate trade deal with Iran
        healthOfficials.Advise(); // # they say we need to spend $50 billion on ObamaCare
    }
}
Run Code Online (Sandbox Code Playgroud)

这种方法允许总统在不知道军事资料,医疗保健或国际外交的情况下从字面上管理国家:详细信息留给专家.总统唯一需要知道的是:"建议()".

你想要什么:

public class MisterPresident
{
    public void RunTheCountry()
    {
        // people walk into the Presidents office and he tells them what to do
        // depending on who they are.

        // Fallujah Advice - Mr Prez tells his military exactly what to do.
        petraeus.IncreaseTroopNumbers();
        petraeus.ImproveSecurity();
        petraeus.PayContractors();

        // Condi diplomacy advice - Prez tells Condi how to negotiate

        condi.StallNegotiations();
        condi.LowBallFigure();
        condi.FireDemocraticallyElectedIraqiLeaderBecauseIDontLikeHim();

        // Health care

        healthOfficial.IncreasePremiums();
        healthOfficial.AddPreexistingConditions();
    }
}
Run Code Online (Sandbox Code Playgroud)

没有!没有!没有!在上述情景中,总统正在做所有的工作:他知道增加部队数量和预先存在的条件.这意味着,如果中东政策发生变化,总统将不得不改变他的命令,以及彼得雷乌斯班.我们只需改变彼得雷乌斯班,因为总统不应该陷入这种细节的困境.他不需要知道细节.他需要知道的是,如果他订购了一份订单,那么一切都将得到妥善处理.所有细节都应留给专家.

这使得总统可以做他最擅长的事情:制定一般政策,看起来很好并打高尔夫:P.

它是如何实际实现的 - 通过基类或通用接口实现的

简而言之,这实际上是多态性.究竟是怎么做到的?通过"实现通用接口" 使用基类(继承) - 请参阅上面的答案,这些答案更清楚地详述了这一点.(为了更清楚地理解这个概念,你需要知道接口是什么,你需要了解继承是什么.没有它,你可能会很困难.)

换句话说,Petraeus,Condi和HealthOfficials都将是"实现接口"的类 - 让我们称之为IAdvisor只包含一种方法的接口:Advise().但现在我们正在深入了解细节.

这将是理想的

    public class MisterPresident
    {
            // You can pass in any advisor: Condi, HealthOfficials,
            //  Petraeus etc. The president has no idea who it will 
            // be. But he does know that he can ask them to "advise" 
            // and that's all Mr Prez cares for.

        public void RunTheCountry(IAdvisor governmentOfficer)
        {             
            governmentOfficer.Advise();              
        }
    }


    public class USA
    {
        MisterPresident president;

        public USA(MisterPresident president)
        {
            this.president = president;
        }

        public void ImplementPolicy()
        {
            IAdvisor governmentOfficer = getAdvisor(); // Returns an advisor: could be condi, or petraus etc.
            president.RunTheCountry(governmentOfficer);
        }
    }
Run Code Online (Sandbox Code Playgroud)

摘要

你真正需要知道的是:

  • 总统不需要知道具体细节 - 这些细节留给其他人.
  • 所有总统需要知道的是询问谁走进门给他建议 - 我们知道他们在被要求提出建议时绝对知道该怎么做(因为他们都是实际的,顾问(或IAdvisors :))

我真的希望它对你有所帮助.如果你发表任何评论都不明白,我会再试一次.

  • 很棒的例子!谢谢。 (4认同)
  • 非常有趣的比喻。谢谢你。 (2认同)
  • @TTT 因为(1)每次你有一个新顾问时,你就必须更改总统级别 - 你不想进行 x2 更改。只有一个。(2) 其次,如果您必须更换现有顾问,那么您可能必须返回并更改总裁类中的这三个调用之一 - 您只想进行一项更改,而不是两次。(3) 如果您接到三个单独的电话,那么您必须在总裁班中询问:“如果是 healthAdvisor?然后这样做:`和`如果彼得劳斯则这样做等等。`这种模式将需要重复,这是不必要和复杂的。请参阅上面的编辑。 (2认同)

Tom*_*ing 24

多态性是将一类对象视为父类的能力.

例如,假设有一个名为Animal的类,以及一个名为Dog的类,它继承自Animal.多态性是将任何Dog对象视为Animal对象的能力,如下所示:

Dog* dog = new Dog;
Animal* animal = dog;
Run Code Online (Sandbox Code Playgroud)

  • 多态性不需要子类型。 (2认同)

Ton*_*ark 22

多态性:

它是面向对象编程的概念.不同对象以自己的方式响应相同消息的能力称为多态.

多态性源于每个类都在其自己的命名空间中.在类定义中指定的名称与在其外部任何位置分配的名称不冲突.这对象的数据结构和对象方法中的实例变量都是如此:

  • 就像C结构的字段在受保护的命名空间中一样,对象的实例变量也是如此.

  • 方法名称也受到保护.与C函数的名称不同,方法名称不是全局符号.一个类中的方法名称不能与其他类中的方法名称冲突; 两个非常不同的类可以实现具有相同名称的方法.

方法名称是对象接口的一部分.当发送消息请求对象执行某些操作时,该消息将命名该对象应执行的方法.因为不同的对象可以具有相同名称的方法,所以必须相对于接收消息的特定对象来理解消息的含义.发送到两个不同对象的相同消息可以调用两个不同的方法.

多态的主要好处是它简化了编程接口.它允许建立可以在课堂上重复使用的约定.您可以重复使用相同的名称,而不是为添加到程序中的每个新函数创建新名称.编程接口可以描述为一组抽象行为,与实现它们的类完全不同.

例子:

示例1:这是一个用Python 2.x编写的简单示例.

class Animal:
    def __init__(self, name):    # Constructor of the class
        self.name = name
    def talk(self):              # Abstract method, defined by convention only
        raise NotImplementedError("Subclass must implement abstract method")

class Cat(Animal):
    def talk(self):
        return 'Meow!'

class Dog(Animal):
    def talk(self):
        return 'Woof! Woof!'

animals = [Cat('Missy'),
           Dog('Lassie')]

for animal in animals:
    print animal.name + ': ' + animal.talk()
Run Code Online (Sandbox Code Playgroud)

示例2:使用方法重载和方法覆盖概念在Java中实现多态性.

让我们考虑Car讨论多态性的例子.选择福特,本田,丰田,宝马,奔驰等品牌,一切都是汽车类型.

但每个都有自己的先进功能和更先进的技术参与其移动行为.

现在让我们创建一个基本类型的汽车

Car.java

public class Car {

    int price;
    String name;
    String color;

    public void move(){
    System.out.println("Basic Car move");
    }

}
Run Code Online (Sandbox Code Playgroud)

让我们实施福特汽车的例子.

福特扩展了Car类型以继承其所有成员(属性和方法).

Ford.java

public class Ford extends Car{
  public void move(){
    System.out.println("Moving with V engine");
  }
}
Run Code Online (Sandbox Code Playgroud)

上面的Ford类扩展了Car类,并且还实现了move()方法.尽管福特通过继承已经可以使用移动方法,但福特仍然以自己的方式实施了该方法.这称为方法覆盖.

Honda.java

public class Honda extends Car{
  public void move(){
    System.out.println("Move with i-VTEC engine");
  }
}
Run Code Online (Sandbox Code Playgroud)

就像福特一样,本田也扩展了Car类型并以自己的方式实现了移动方法.

方法覆盖是启用多态性的重要特征.使用方法覆盖,Sub类型可以通过继承更改方法的工作方式.

PolymorphismExample.java

public class PolymorphismExample {
  public static void main(String[] args) {
    Car car = new Car();
    Car f = new Ford();
    Car h = new Honda();

    car.move();
    f.move();
    h.move();

  }
}
Run Code Online (Sandbox Code Playgroud)

多态性示例输出:

在PolymorphismExample类主方法中,我创建了三个对象 - 汽车,福特和本田.所有三个对象都由Car类型引用.

请注意这里的重点是超类类型可以引用Sub类类型的对象,但反之亦然.原因是超类的所有成员都可以使用继承来使用子类,并且在编译期间,编译器会尝试评估我们使用的引用类型是否具有他试图访问的方法.

因此,对于PolymorphismExample中的引用car,f和h,移动方法存在于Car类型中.因此,编译器通过编译过程没有任何问题.

但是当涉及运行时执行时,虚拟机会调用作为子类型的对象的方法.因此,方法move()从它们各自的实现中调用.

因此,所有对象都是Car类型,但在运行时,执行依赖于调用发生的Object.这称为多态性.


Jes*_*erE 12

通常,这指的是类型A的对象的行为类似于B类对象的能力.在面向对象的编程中,这通常通过继承来实现.一些维基百科链接阅读更多:

编辑:修复断开的链接.

  • "A类对象的行为类似于B类对象的能力" - 这不是准确的定义.我会说它更像是处理类型A的对象的能力,就像它是B类的对象一样. (10认同)

Vin*_*vic 9

多态性是这样的:

class Cup {
   int capacity
}

class TeaCup : Cup {
   string flavour
}

class CoffeeCup : Cup {
   string brand
}

Cup c = new CoffeeCup();

public int measure(Cup c) {
    return c.capacity
}
Run Code Online (Sandbox Code Playgroud)

你可以通过一个杯子而不是一个特定的实例.这有助于实现一般性,因为您不必为每种杯子类型提供特定的measure()实例

  • 这是特定的亚型多态性. (2认同)

Abe*_*ler 8

我知道这是一个较老的问题,有很多好的答案,但我想包括一句话答案:

处理派生类型,就好像它是基类型一样.

上面有很多例子说明了这一点,但我觉得这是一个很简洁的答案.

  • 这是子类型,这只是一种多态性. (2认同)

Kca*_*evo 8

(我正在浏览关于完全不同的东西的另一篇文章......并且多态性突然出现......现在我以为我知道多态性是什么......但显然不是以这种美妙的方式解释的......想要把它写在某处......更好还是会分享...)

http://www.eioba.com/a/1htn/how-i-explained-rest-to-my-wife

请阅读本部分:

.....多态性.这是一种令人讨厌的说法,即不同的名词可以使用相同的动词.


Ste*_*art 5

一般而言,它是使用相同或表面上相似的API来连接许多不同类型的对象的能力。有多种形式:

  • 函数重载:定义多个具有相同名称和不同参数类型的函数,例如sqrt(float),sqrt(double)和sqrt(complex)。在大多数允许这样做的语言中,编译器会针对要传递给它的参数类型自动选择正确的参数,因此这是编译时多态性。

  • OOP中的虚拟方法:类的方法可以有多种实现方式,可根据其子类的具体情况进行定制;据说这些方法都覆盖了基类中给出的实现。给定一个对象可能是基类或其任何子类,则在运行中选择正确的实现,因此这是运行时多态。

  • 模板:某些OO语言的功能,可以通过类型对函数,类等进行参数化。例如,您可以定义一个通用的“列表”模板类,然后将其实例化为“整数列表”,“字符串列表”,甚至是“字符串列表列表”等。通常,您为任意元素类型的数据结构编写一次代码,然后编译器为各种元素类型生成该代码的版本。