多态

时间:2024-03-24 15:58:28编辑:奇事君

多态是如何实现的?

多态首先是建立在继承的基础上的,先有继承才能有多态。多态是指不同的子类在继承父类后分别都重写覆盖了父类的方法,即父类同一个方法,在继承的子类中表现出不同的形式。多态成立的另一个条件是在创建子类时候必须使用父类new子类的方式。多态(Polymorphism)按字面的意思就是“多种状态”。在面向对象语言中,接口的多种不同的实现方式即为多态。引用Charlie Calverts对多态的描述——多态性是允许你将父对象设置成为一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作(摘自“Delphi4 编程技术内幕”)。简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。多态性在Object Pascal和C++中都是通过虚函数实现的。拓展资料:多态指同一个实体同时具有多种形式。它是面向对象程序设计(OOP)的一个重要特征。如果一个语言只支持类而不支持多态,只能说明它是基于对象的,而不是面向对象的。C++中的多态性具体体现在运行和编译两个方面。运行时多态是动态多态,其具体引用的对象在运行时才能确定。编译时多态是静态多态,在编译时就可以确定对象使用的形式。多态:同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。在运行时,可以通过指向基类的指针,来调用实现派生类中的方法。C++中,实现多态有以下方法:虚函数,抽象类,覆盖,模板(重载和多态无关)。OC中的多态:不同对象对同一消息的不同响应.子类可以重写父类的方法。多态就是允许方法重名 参数或返回值可以是父类型传入或返回。多态也指生物学中腔肠动物的特殊的生活方式。水螅态与水母态的世代交替现象。把不同的子类对象都当作父类来看,可以屏蔽不同子类对象之间的差异,写出通用的代码,做出通用的编程,以适应需求的不断变化。赋值之后,父类型的引用就可以根据当前赋值给它的子对象的特性以不同的方式运作。也就是说,父亲的行为像儿子,而不是儿子的行为像父亲。使用继承性的结果就是当创建了一个类的家族,在认识这个类的家族时,就是把子类的对象当作基类的对象,这种认识又叫作upcasting(向上转型)。这样认识的重要性在于:我们可以只针对基类写出一段程序,但它可以适应于这个类的家族,因为编译器会自动找出合适的对象来执行操作。这种现象又称为多态性。而实现多态性的手段又叫称动态绑定(dynamic binding)。简单的说,建立一个父类对象的引用,它所指对象可以是这个父类的对象,也可以是它的子类的对象。java中当子类拥有和父类同样的函数,当通过这个父类对象的引用调用这个函数的时候,调用到的是子类中的函数。

多态的意义在于什么?

什么是多态?可以这么回答:父类引用引用子类对象父类和子类有同名的覆盖方法通过父类引用调用这个重写的方法的时候。多数的话就可以称为多态,单数可以说运行时绑定。使用多态有什么好处?类调用者对类的使用成本进一步降低封装是让类的调用者不需要知道类的实现细节,多态能让类的调用者连这个类的类型是什么都不必知道,只需要知道这个对象具有某个方法即可。因此,多态可以理解成是封装的更进一步,让类调用者对类的使用成本进一步降低。能够降低代码的“圈复杂度”,避免使用大量的if-else多态在代码中的体现:输出结果:猫吃鱼猫吃鱼(因为描述的是真正的是一只猫)拓展:多态性:同一操作作用于不同的对象,可以用不同的解释,产生不同的执行结果,这就是多态性。多态性通过派生类覆写基类中的虚函数的方法来实现。多态性分为两种,一种是编译时的多态性,一种是运行时的多态性。编译时的多态性:编译时多态是通过重载来实现的。对于非虚的成员来说,系统在编译时,根据传递的参数,返回的类型等信息决定实现何种操作。运行时的多态性:运行时的多态性就是指直到系统运行时,才根据实际情况决定实现何种操作。

多态的概念是什么?

多态(英语:polymorphism)指为不同数据类型的实体提供统一的接口。 多态类型(英语:polymorphic type)可以将自身所支持的操作套用到其它类型的值上。在编程语言和类型论中,多态(英语:polymorphism)指为不同数据类型的实体提供统一的接口。多态类型(英语:polymorphic type)可以将自身所支持的操作套用到其它类型的值上。多态的种类:动态多态(dynamic polymorphism):通过类继承机制和虚函数机制生效于运行期。可以优雅地处理异质对象集合,只要其共同的基类定义了虚函数的接口。也被称为子类型多态(Subtype polymorphism)或包含多态(inclusion polymorphism)。在面向对象程序设计中,这被直接称为多态。静态多态(static polymorphism):模板也允许将不同的特殊行为和单个泛化记号相关联,由于这种关联处理于编译期而非运行期,因此被称为“静态”。可以用来实现类型安全、运行高效的同质对象集合操作。以上内容参考:百度百科-多态性

多态的概念是什么?

多态(英语:polymorphism)指为不同数据类型的实体提供统一的接口。 多态类型(英语:polymorphic type)可以将自身所支持的操作套用到其它类型的值上。计算机程序运行时,相同的消息可能会送给多个不同的类别之对象,而系统可依据对象所属类别,引发对应类别的方法,而有不同的行为。简单来说,所谓多态意指相同的消息给予不同的对象会引发不同的动作。多态也可定义为“一种将不同的特殊行为和单个泛化记号相关联的能力”。多态的历史1967年,英国计算机科学家克里斯托弗·斯特雷奇在他的讲义合集《编程语言中的基础概念》中,首次提出了特设多态和参数多态的概念。1985 年,彼得·瓦格纳和卢卡·卡代利在论文中引入了术语“蕴含多态”(英语:inclusion polymorphism)来为子类型和继承 (计算机科学)建模。不过子类型和继承本身在 1967 年就已经在Simula有对应的实现。

什么体现了类的多态性?

多态是通过:
  1 接口 和 实现接口并覆盖接口中同一方法的几不同的类体现的
  2 父类 和 继承父类并覆盖父类中同一方法的几个不同子类实现的.
  一、基本概念
  多态性:发送消息给某个对象,让该对象自行决定响应何种行为。
  通过将子类对象引用赋值给超类对象引用变量来实现动态方法调用。
  java 的这种机制遵循一个原则:当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法。
  1. 如果a是类A的一个引用,那么,a可以指向类A的一个实例,或者说指向类A的一个子类。
  2. 如果a是接口A的一个引用,那么,a必须指向实现了接口A的一个类的实例。

二、Java多态性实现机制
  SUN目前的JVM实现机制,类实例的引用就是指向一个句柄(handle)的指针,这个句柄是一对指针:
  一个指针指向一张表格,实际上这个表格也有两个指针(一个指针指向一个包含了对象的方法表,另外一个指向类对象,表明该对象所属的类型);
  另一个指针指向一块从java堆中为分配出来内存空间。
  三、总结
  1、通过将子类对象引用赋值给超类对象引用变量来实现动态方法调用。
  DerivedC c2=new DerivedC();
  BaseClass a1= c2; //BaseClass 基类,DerivedC是继承自BaseClass的子类
  a1.play(); //play()在BaseClass,DerivedC中均有定义,即子类覆写了该方法
  分析:
  * 为什么子类的类型的对象实例可以覆给超类引用?
  自动实现向上转型。通过该语句,编译器自动将子类实例向上移动,成为通用类型BaseClass;
  * a.play()将执行子类还是父类定义的方法?
  子类的。在运行时期,将根据a这个对象引用实际的类型来获取对应的方法。所以才有多态性。一个基类的对象引用,被赋予不同的子类对象引用,执行该方法时,将表现出不同的行为。
  在a1=c2的时候,仍然是存在两个句柄,a1和c2,但是a1和c2拥有同一块数据内存块和不同的函数表。
  2、不能把父类对象引用赋给子类对象引用变量
  BaseClass a2=new BaseClass();
  DerivedC c1=a2;//出错
  在java里面,向上转型是自动进行的,但是向下转型却不是,需要我们自己定义强制进行。
  c1=(DerivedC)a2; 进行强制转化,也就是向下转型.
  3、记住一个很简单又很复杂的规则,一个类型引用只能引用引用类型自身含有的方法和变量。
  你可能说这个规则不对的,因为父类引用指向子类对象的时候,最后执行的是子类的方法的。
  其实这并不矛盾,那是因为采用了后期绑定,动态运行的时候又根据型别去调用了子类的方法。而假若子类的这个方法在父类中并没有定义,则会出错。
  例如,DerivedC类在继承BaseClass中定义的函数外,还增加了几个函数(例如 myFun())
  分析:
  当你使用父类引用指向子类的时候,其实jvm已经使用了编译器产生的类型信息调整转换了。
  这里你可以这样理解,相当于把不是父类中含有的函数从虚拟函数表中设置为不可见的。注意有可能虚拟函数表中有些函数地址由于在子类中已经被改写了,所以对象虚拟函数表中虚拟函数项目地址已经被设置为子类中完成的方法体的地址了。
  4、Java与C++多态性的比较
  jvm关于多态性支持解决方法是和c++中几乎一样的,
  只是c++中编译器很多是把类型信息和虚拟函数信息都放在一个虚拟函数表中,但是利用某种技术来区别。
  Java把类型信息和函数信息分开放。Java中在继承以后,子类会重新设置自己的虚拟函数表,这个虚拟函数表中的项目有由两部分组成。从父类继承的虚拟函数和子类自己的虚拟函数。
  虚拟函数调用是经过虚拟函数表间接调用的,所以才得以实现多态的。
  Java的所有函数,除了被声明为final的,都是用后期绑定。
  四. 1个行为,不同的对象,他们具体体现出来的方式不一样,
  比如: 方法重载 overloading 以及 方法重写(覆盖)override
  class Human{
  void run(){输出 人在跑}
  }
  class Man extends Human{
  void run(){输出 男人在跑}
  }
  这个时候,同是跑,不同的对象,不一样(这个是方法覆盖的例子)
  class Test{
  void out(String str){输出 str}
  void out(int i){输出 i}
  }
  这个例子是方法重载,方法名相同,参数表不同
  ok,明白了这些还不够,还用人在跑举例
  Human ahuman=new Man();
  这样我等于实例化了一个Man的对象,并声明了一个Human的引用,让它去指向Man这个对象
  意思是说,把 Man这个对象当 Human看了.
  比如去动物园,你看见了一个动物,不知道它是什么, "这是什么动物? " "这是大熊猫! "
  这2句话,就是最好的证明,因为不知道它是大熊猫,但知道它的父类是动物,所以,
  这个大熊猫对象,你把它当成其父类 动物看,这样子合情合理.
  这种方式下要注意 new Man();的确实例化了Man对象,所以 ahuman.run()这个方法 输出的 是 "男人在跑 "
  如果在子类 Man下你 写了一些它独有的方法 比如 eat(),而Human没有这个方法,
  在调用eat方法时,一定要注意 强制类型转换 ((Man)ahuman).eat(),这样才可以...
  对接口来说,情况是类似的...
  实例:
  package domatic;
  //定义超类superA
  class superA {
  int i = 100;
  void fun(int j) {
  j = i;
  System.out.println("This is superA");
  }
  }
  // 定义superA的子类subB
  class subB extends superA {
  int m = 1;
  void fun(int aa) {
  System.out.println("This is subB");
  }
  }
  // 定义superA的子类subC
  class subC extends superA {
  int n = 1;
  void fun(int cc) {
  System.out.println("This is subC");
  }
  }

class Test {
  public static void main(String[] args) {
  superA a = new superA();
  subB b = new subB();
  subC c = new subC();
  a = b;
  a.fun(100);
  a = c;
  a.fun(200);
  }
  }
  /*
  * 上述代码中subB和subC是超类superA的子类,我们在类Test中声明了3个引用变量a, b,
  * c,通过将子类对象引用赋值给超类对象引用变量来实现动态方法调用。也许有人会问:
  * "为什么(1)和(2)不输出:This is superA"。
  * java的这种机制遵循一个原则:当超类对象引用变量引用子类对象时,
  * 被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,
  * 但是这个被调用的方法必须是在超类中定义过的,
  * 也就是说被子类覆盖的方法。
  * 所以,不要被上例中(1)和(2)所迷惑,虽然写成a.fun(),但是由于(1)中的a被b赋值,
  * 指向了子类subB的一个实例,因而(1)所调用的fun()实际上是子类subB的成员方法fun(),
  * 它覆盖了超类superA的成员方法fun();同样(2)调用的是子类subC的成员方法fun()。
  * 另外,如果子类继承的超类是一个抽象类,虽然抽象类不能通过new操作符实例化,
  * 但是可以创建抽象类的对象引用指向子类对象,以实现运行时多态性。具体的实现方法同上例。
  * 不过,抽象类的子类必须覆盖实现超类中的所有的抽象方法,
  * 否则子类必须被abstract修饰符修饰,当然也就不能被实例化了
  */
  以上大多数是以子类覆盖父类的方法实现多态.下面是另一种实现多态的方法-----------重写父类方法
  1.JAVA里没有多继承,一个类之能有一个父类。而继承的表现就是多态。一个父类可以有多个子类,而在子类里可以重写父类的方法(例如方法print()),这样每个子类里重写的代码不一样,自然表现形式就不一样。这样用父类的变量去引用不同的子类,在调用这个相同的方法print()的时候得到的结果和表现形式就不一样了,这就是多态,相同的消息(也就是调用相同的方法)会有不同的结果。举例说明:
  //父类
  public class Father{
  //父类有一个打孩子方法
  public void hitChild(){
  }
  }
  //子类1
  public class Son1 extends Father{
  //重写父类打孩子方法
  public void hitChild(){
  System.out.println("为什么打我?我做错什么了!");
  }
  }
  //子类2
  public class Son2 extends Father{
  //重写父类打孩子方法
  public void hitChild(){
  System.out.println("我知道错了,别打了!");
  }
  }
  //子类3
  public class Son3 extends Father{
  //重写父类打孩子方法
  public void hitChild(){
  System.out.println("我跑,你打不着!");
  }
  }
  //测试类
  public class Test{
  public static void main(String args[]){
  Father father;
  father = new Son1();
  father.hitChild();
  father = new Son2();
  father.hitChild();
  father = new Son3();
  father.hitChild();
  }
  }
  都调用了相同的方法,出现了不同的结果!这就是多态的表现!


上一篇:曹博文

下一篇:仅仅是朋友