-
多态:多态指的是编译时类型变化,而运行时类型不变
2020-07-23 12:45:34多态:多态指的是编译时类型变化,而运行时类型不变。 多态分两种: ① 编译时多态:编译时动态重载; ② 运行时多态:指一个对象可以具有多个类型。 对象是客观的,人对对象的认识是主观的。 例: 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); } }
-
python中多态是什么意思_python类的多态是什么
2020-12-09 04:28:24多态是指不同的子类在继承父类后分别都重写覆盖了父类的方法,即父类同一个方法,在继承的子类中表现出不同的形式。多态成立的另一个条件是在创建子类时候必须使用父类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:121什么是多态? 多态是指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多态是继封装、继承之后,面向对象的第三大特征 什么是多态 是指同一方法,对于不同的对象具有多个不同的实现 多态的前提 必须要有继承或者实现的关系 父类引用指向子类对象【格式体现】 方法重写【意义体现:不...多态
多态是继封装、继承之后,面向对象的第三大特征
多态的概念
是指同一方法,对于不同的对象具有多个不同的实现
多态的前提
- 必须要有继承或者实现的关系
- 父类引用指向子类对象【格式体现】
- 方法重写【意义体现:不重写多态的意义就不存在了】
实现多态
- 创建父类
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;//安全转换 }
-
什么是多态python_java基础中的多态是什么?如何实现?
2020-12-29 05:00:13我们在实现一种程序运行时,可以选择不同的...一、定义多态是指的是事物的多种状态,同一操作,由于条件的不同,所以产生的结果也不同。例如在程序中同一引用类型,由于实例的不同,产生的结果也会不同。二、说明1...