精华内容
下载资源
问答
  • 多态多态指编译时类型变化,而运行时类型不变。 多态分两种: ① 编译时多态:编译时动态重载; ② 运行时多态一个对象可以具有多个类型。 对象客观的,人对对象的认识主观的。 例: Animal a=new Dog...

    多态:多态指的是编译时类型变化,而运行时类型不变。
    多态分两种:
    ① 编译时多态:编译时动态重载;
    ② 运行时多态:指一个对象可以具有多个类型。
    对象是客观的,人对对象的认识是主观的。
    例:
    Animal a=new Dog();查看格式名称;
    Dog d=(Dog)a。声明父类来引用子类。
    (思考上面的格式)

    package TomText;
    
    public class TomText_19 {
    
        public static void link(String a)
          {
          a+="word";
          System.out.println(a);
          }
          public static void main(String []args)
          {
          String a="hello";
          link(a);
          System.out.println(a);
    
          }
    }
    
    展开全文
  • 多态是指不同的子类在继承父类后分别都重写覆盖了父类的方法,即父类同一个方法,在继承的子类中表现出不同的形式。多态成立的另一个条件是在创建子类时候必须使用父类new子类的方式。Fuf1=newZi1();Fuf2=newZi2();...

    多态首先是建立在继承的基础上的,先有继承才能有多态。多态是指不同的子类在继承父类后分别都重写覆盖了父类的方法,即父类同一个方法,在继承的子类中表现出不同的形式。多态成立的另一个条件是在创建子类时候必须使用父类new子类的方式。Fu f1 = new Zi1();

    Fu f2 = new Zi2();

    f1.c();

    f2.c();

    子类Zi1,Zi2继承了父类Fu,并且重写了父类的方法c()

    然后通过f1,和f2去调用子类重写父类后的这个方法。即还有一个成立条件是子类必须重写父类的方法。

    面向对象的三个基本特征是:封装、继承、多态。

    比如,你和你朋友同时继承了人这个类中打人的方法,但是你用拳头打人和你朋友用巴掌打人的方法都是打人方法,却表现出不同的形式,这就是现实生活中多态的理解。

    关于多态,有一个被称作“鸭子类型”(duck typeing)的东西,其含义在维基百科中被表述为:

    在程序设计中,鸭子类型(英语:duck typing)是动态类型的一种风格。在这种风格中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由当前方法和属性的集合决定。这个概念的名字来源于由 James Whitcomb Riley 提出的鸭子测试(见下面的“历史”章节),“鸭子测试”可以这样表述:“当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。”

    在 python 中多态的经典使用可以用两句话来总结对扩展开放和对修改封闭,即著名的「开闭」原则。对扩展开放即可以随意的增加父类的子类;对修改封闭即对于依赖父类的函数,新增子类对该函数无任何影响无需做任何修改。

    我们可以通过以下代码来加深理解:#!/usr/bin/env python3

    # -*- coding:utf-8 -*-

    class Person:

    def __init__(self, name, age):

    self.name = name

    self.age = age

    def print_age(self):

    print("%s's age is %s" % (self.name, self.age))

    class Man(Person):

    def print_age(self):

    print("Mr. %s's age is %s" %(self.name, self.age))

    class Woman(Person):

    def print_age(self):

    print("Ms. %s's age is %s" %(self.name, self.age))

    def person_age(person):

    person.print_age()

    person = Person("kevin", 23)

    man = Man("Bob", 33)

    woman = Woman("Lily", 28)

    person_age(person)

    person_age(man)

    person_age(woman)

    以上代码执行结果如下:kevin's age is 23

    Mr. Bob's age is 33

    Ms. Lily's age is 28

    在以上代码中函数 person_age 函数的输入参数为类 Person 的实例,但是在实际执行过程中 Person 的子类 Man 和 Woman 的示例同样可以在 person_age 函数中正常运行,这既是类的多态的作用。实际上任何实现了函数 print_age 函数的类均可作为 person_age 函数的参数且能够正常工作,这既是前面提到的「鸭子类型」。

    展开全文
  • 什么是多态

    2014-09-28 23:06:12
    1什么是多态? 多态是指

    1什么是多态?TC++PL p277-278

    基类通过声明并定义一系列虚函数,继承它的派生类可以重新定义基类中的这些虚函数,从而覆盖基类的版本。在调用的时候,总能正确地调用对应的虚函数版本,不管实际的对象(即p)是被声明为基类的对象还是派生类的对象,也不管指向对象的指针或引用的是基类类型还是派生类类型。这就是所谓的多态。

    更直白一点,类的对象调用的是哪个版本的虚函数,跟指向对象的指针类型无关(基类或派生类),只跟对象的虚函数表指针指向的虚函数表的元素(元素即类的所有虚函数指针)有关。这样,类的对象总是能调用正确的虚函数版本,即基类的对象总能调用基类的虚函数版本,派生类的对象总是调用派生类的虚函数版本。而这一切不依赖于指向对象的指针或引用的类型。这就是多态!所以才说对象必须通过指针或引用去操作

    能实现这种多态的原因:

    1)当然,编译器为每个存在虚函数的类生成一个虚函数表,同时生成一个指向该表的指针。而同时为类的所有对象都生成一个指向该表的指针。这是实现多态的内部机制。

    2)其次,要利用指针变量(p)的类型并不会改变指针变量指向的存储地址(这个地址存的哪个版本的虚函数,那么调用的就是哪个版本)这一特点,而通过对虚函数的间接访问(即访问虚函数的地址来调用虚函数),这样就能保证准确无误地调用对应的虚函数。

    3)而如果是用下面右边的这种方式,Base p=d;这就是创建了一个base类的对象p,这个p的虚函数表指针肯定是指向base类的虚函数表。

    4)所以,对象必须通过指针或引用去操作,才能取得C++的多态性行为。

    Derived d(3);                                                          Derived d(3);

    Base* p=&d;                                                          Base p=d;//这个算强制类型转换吗

    p->display();//调用派生类版本                             p.display();//调用基类版本

    要在c++中取得多态行为,被调用的函数就必须是虚函数,而对象则必须是通过指针或引用去操作的。否则编译器就会知道对象的确切类型,也就不需要运行时的多态性了。话说正是这句话不咋明白啊。。。通过指针或引用去操作的时候,编译器不知道对象的确切类型吗?因为在运行时进行动态绑定?但动态绑定又是个毛啊???

    2虚函数的实现机制?

    1)有虚函数的基类或派生类,编译器都为他们生成一个虚函数表(vtbl),这个虚函数表可以看成是一个数组(不同编译器实现方式不同,有的用链表实现,但原理是一样的),这个数组的元素就是该类的所有虚函数的指针,这些指针分别指向一个虚函数(其实存储的就是虚函数的地址,用指针访问)。

    2)然后,编译器为每个带虚函数的类置入一个指针(虚函数表指针,vptr),这个指针指向类的vtbl。

    3)声明对象时,每个对象都有一个虚函数表指针,这个vptr都被初始化为指向类的vtbl。所有对象共享一份vtbl(其实看编译器怎么实现了,因为在链接所有objective文件的时候,可能一份vtbl并不够用,这时候有的编译器会生成几分拷贝的vtbl,在生成程序成功后再删除这些拷贝)。

    4)至于类的内存大小的计算,虚函数的调用可以参考hackbuteer1的文章:

    3为什么用虚函数来实现多态?

    为了解决类型域检查方案中的缺陷,这个方案要求遍历检查当前对象是哪个类的对象,这样时间复杂度太高,不仅影响性能,而且也不适合维护。因为一旦新定义一个派生类,就要修改这个类型域检查的代码。当然,虚函数来实现多态的代价就是要损失一些存储空间,是一个以空间换时间的方案。参考hackbuteer1文章中两种多态实现的优缺点对比。

    展开全文
  • 多态

    2020-04-18 10:30:18
    多态是继封装、继承之后,面向对象的第三大特征 什么是多态 是指同一方法,对于不同的对象具有多个不同的实现 多态的前提 必须要有继承或者实现的关系 父类引用指向子类对象【格式体现】 方法重写【意义体现:不...

    多态

    多态是继封装、继承之后,面向对象的第三大特征

    多态的概念

    是指同一方法,对于不同的对象具有多个不同的实现

    多态的前提

    1. 必须要有继承或者实现的关系
    2. 父类引用指向子类对象【格式体现】
    3. 方法重写【意义体现:不重写多态的意义就不存在了】

    实现多态

    • 创建父类
    public class Father {
        public void method(){
            System.out.println("父类的method方法");
        }
    }
    
    • 创建两子类,并重写父类中的方法
    public class Son1 extends Father {
        @Override
        public void method() {
            System.out.println("子类1的method方法");
        }
    }
    
    public class Son2 extends Father {
        @Override
        public void method() {
            System.out.println("子类2的method方法");
        }
    }
    
    • 创建测试类,使父类引用指向子类对象
    public class Test {
        public static void main(String[] args) {
            Father father1 = new Son1();//父类引用指向子类对象,此时父类和子类构成多态 同一方法有两种不同的实现方式
            Father father2 = new Son2();
            father1.method();//此时调用的是子类1中的method
            father2.method();//此时调用的是子类2中的method
        }
    }
    

    运行结果

    子类1的method方法
    子类2的method方法
    

    多态访问成员的特点

    • 多态时成员变量的访问特点
      • 编译看左边,运行看左边
        • 简而言之:多态的情况下,访问的是父类的成员变量
    • 多态时成员方法的访问特点
      • 非静态方法:编译看左边,运行看右边
        • 简而言之:编译的时候去父类中查找方法,运行的时候去子类中查找方法来执行
      • 静态方法:编译看左边,运行看左边
        • 简而言之:编译的时候去父类中查找方法,运行的时候去父类中查找方法来执行
    • 注意:多态的情况下是无法访问子类独有的方法

    记忆方法: 只有非静态成员方法,编译看左边,运行看右边;其他成员都是,编译看左边,运行也看左边

    • 代码演示 创建Animal类作为父类,创建Dog类作为子类,创建测试类对成员的访问进行测试
    public class Animal {
        int age = 10;
        public void eat(){
            System.out.println("动物吃东西");
        }
        public static void sleep(){
            System.out.println("动物睡觉");
        }
    }
    
    public class Dog extends Animal {
        int age = 20;
    
        @Override
        public void eat() {
            System.out.println("狗吃骨头");
        }
        //@Override //子类无法继承父类的静态方法
        public static void sleep(){
            System.out.println("狗睡觉");
        }
    }
    
    public class Test {
        public static void main(String[] args) {
            Animal anl = new Dog();
            System.out.println(anl.age);
            anl.eat();
            anl.sleep();
        }
    }
    

    运行结果:

    10
    狗吃骨头
    动物睡觉
    

    多态的表现形式

    • 普通父类多态
    • 抽象类多态
    • 接口多态
    class Father{}
    class Son extends Father{}
    public class Demo{
        public static void main(String[] args){
            Father f = new Son();//左边是一个“父类”
        }
    }
    
    abstract class Father{}
    class Son extends Father{}
    public class Demo{
        public static void main(String[] args){
            Father f = new Son();//左边是一个“父类”
        }
    }
    
    interface A{}
    class AImpl implements A{}
    public class Demo{
        public static void main(String[] args){
            A a = new AImpl();
        }
    }
    

    多态的应用场景

    • 变量多态
    • 参数多态
    • 返回值多态
    • 创建Animal父类和Dog Cat两个子类 在Demo中对多态的三种应用场景进行测试
    public class Animal {
        public void eat(){
            System.out.println("动物吃东西");
        }
    }
    
    public class Dog extends Animal {
        @Override
        public void eat() {
            System.out.println("狗吃骨头");
        }
    }
    
    public class Cat extends Animal {
        @Override
        public void eat() {
            System.out.println("猫吃鱼");
        }
    }
    
    public class Demo {
        public static void main(String[] args) {
            // 1.变量多态
            Animal anl = new Dog();
            anl.eat();
    
            // 2.形参多态
            Dog dog = new Dog();
            invokeEat(dog);
            Cat cat = new Cat();
            invokeEat(cat);// 实参赋值给形参: Animal anl = new Cat();
    
            // 3.返回值多态
            Animal anl2 = getAnimal();// 返回值赋值给变量: Animal anl2 = new Dog()
        }
        
        // 2.形参多态: 当你调用invokeEat方法的时候,传入Animal类的子类对象
        // 结论:如果方法的参数是父类类型,那么就可以接收所有该父类对象以及其所有子类对象
        // 注意:Object类:是java中所有类的父类,所以如果参数为Object类型,那么就可以传入一切类的对象
        public static void invokeEat(Animal anl){
            anl.eat();
        }
        
        //  3.返回值多态
        // 结论:如果方法的返回值类型为父类类型,那么就可以返回该父类对象以及其所有子类对象
        public static Animal getAnimal(){
            //return new Animal();
            return new Dog();
            //return new Cat();
        }
    }
    

    多态的好处和弊端

    • 好处:提高了代码的扩展性
    • 弊端:父类只能调用父类的共性内容,不能调用子类特有的内容
    • 创建Animal抽象类作为父类,创建Dog Cat类继承Animal类并重写eat方法 在Cat中创建一个特有的方法 并创建Test类进行测试
    public abstract class Animal {
        public abstract void eat();
    }
    
    public class Dog extends Animal{
        @Override
        public void eat() {
            System.out.println("狗吃骨头");
        }
    }
    
    public class Cat extends Animal {
        @Override
        public void eat() {
            System.out.println("猫吃鱼");
        }
        public void catchMouse(){
            System.out.println("猫抓老鼠");
        }
    }
    
    //多态好处测试
    public class Test {
        public static void main(String[] args) {
            //创建猫对象
            Cat cat = new Cat();
            //创建狗对象
            Dog dog = new Dog();
            //如果没有多态,我们需要创建两个方法,分别调用两个对象的eat方法
            showCatEat(cat);
            showDogEat(dog);
            //如果使用多态,那么我们只需要创建一个方法就可以实现两个对象不同eat方法的调用
            showAnimalEat(cat);
            showAnimalEat(dog);
    
        }
        public static void showCatEat(Cat cat){
            cat.eat();
        }
        public static void showDogEat(Dog dog){
            dog.eat();
        }
        public static void showAnimalEat(Animal anl){
            anl.eat();
        }
    }
    

    运行结果:

    猫吃鱼
    狗吃骨头
    猫吃鱼
    狗吃骨头
    
    //多态的弊端
    public class Test2 {
        public static void main(String[] args) {
            Animal anl = new Cat();
            anl.catchMouse();//编译错误 编译看左边父类中没有定义catchMouse方法
        }
    }
    

    引用类型转型

    向上转型
    • 子类类型向父类类型向上转换的过程,这个过程是默认的。
       Aniaml anl = new Cat();  
    
    向下转型
    • 父类类型向子类类型向下转换的过程,这个过程是强制的。
       Aniaml anl = new Cat();  
       Cat c = (Cat)anl;//向下转型
       c.catchMouse();// 可以访问 子类独有的功能,解决多态的弊端
    
    instanceof关键字
    • 向下强转有风险,最好在转换前做一个验证 :

    • 格式:

      变量名 instanceof 数据类型 
      如果变量属于该数据类型,返回true。
      如果变量不属于该数据类型,返回false
      if( anl instanceof Cat){//判断anl是否能转换为Cat类型,如果可以返回:true,否则返回:false
          Cat c = (Cat)anl;//安全转换
      }
    
    展开全文
  • 我们在实现一种程序运行时,可以选择不同的...一、定义多态是指的是事物的多种状态,同一操作,由于条件的不同,所以产生的结果也不同。例如在程序中同一引用类型,由于实例的不同,产生的结果也会不同。二、说明1...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 6,688
精华内容 2,675
关键字:

多态是指