-
2021-11-10 19:31:19
什么是编译时
只是单纯的将代码翻译成一种中间语言(例如:java代码被编译后生成字节码文件)
编译时会做一些代码语法的检查提醒
编译时没有实质性的为代码分配内存空间运行,所以可以说编译是静态类型检查
什么是运行时
为代码分配空间,让代码跑起来
此时可能会出现编译时发现不了的错误(例如:数组越界问题,由于编译时并未分配空间,所以是无法检查出这个问题的)
什么是Java编译时多态
通过编译即可明确是哪一个多态方法的调用
-
比如说Java的重载,只通过参数的数量和类型不同来实现多态,那么在编译时我们可以单纯根据语法就能知道会调用哪一个重载的方法,所以所有的重载都是编译时多态
-
再比如说Java的覆写,通过本类的对象引用指向本类的对象,可以明确是调用本类的覆写方法
什么是Java运行时多态
通过运行才能明确是哪一个多态方法的调用
例如,Java有一个语法:父类的引用可以指向子类的对象,并且可以通过父类引用使用父子类共有的方法
那么调用该方法时,使用哪个类中的方法呢
这个问题光靠编译是解决不了的
我认为是在代码运行后,在子类的方法栈中看具体有该方法,若没有,再通过继承关系逐级向上从父类的方法栈中寻找,直到找到为止
运行时多态有什么作用呢
用代码模拟现实的业务逻辑需求,但是生活中的需求会不断改变,那么代码也要跟着翻天覆地的“重写”吗?
以下面的代码为例
class Shape{ void printArea(){} } class square extends Shape{ void printArea(){} } /* 例如新增加一个需求,只需要实现新的需求,原先的代码,“接口”保持不动 class circle extends Shape{ void printArea(){} } */ class users{ void GetArea(Shape s){ //由于这里是父类的引用,可以指向所有子类,所以增添新的子类,这里也不用改变,体现代码的可拓展 s.printArea(); } /* 如果不用运行时多态,那么在新的需求需要实现时,你需要不断地增添 void GetArea(square s){ s.printArea(); } void GetArea(circle c){ c.printArea(); } . . . */ } class Test{ public static void main(String[] msg){ new users().GetArea(new square()); //假如用户还想知道其他的形状的面积,只需要new users().GetArea(new circle()); } } //在现实生活中,列不完的需求出现时,运行时多态即可体现它的好处
更多相关内容 -
-
java的编译时多态和运行时多态
2015-04-14 10:23:19java的编译时多态和运行时多态,保证一看就会 -
C++编译时多态和运行时多态
2021-05-15 22:44:20多态编译时多态运行时多态两种多态的优缺点 编译时多态 编译时多态,又叫静态多态、早绑定。编译时多态基于template(模板)的具现化与函数的重载解析,这种多态在编译期进行,因此称为编译期多态。 1.模板具现化 以...编译时多态
编译时多态,又叫静态多态、早绑定。编译时多态基于template(模板)的具现化与函数的重载解析,这种多态在编译期进行,因此称为编译期多态。
注意:重载不关心函数返回类型,只关心函数的参数个数、参数类型或参数顺序。
1.模板具现化
以不同的模板参数具现化导致调用不同的函数,如下:class Animal { public : void shout() { cout << "发出动物的叫声" << endl; }; }; class Dog { public: void shout(){ cout << "汪汪!"<<endl; } }; class Cat { public: void shout(){ cout << "喵喵~"<<endl; } }; class Bird { public: void shout(){ cout << "叽喳!"<<endl; } }; template <typename T> void animalShout(T & t) { t.shout(); } int main() { Animal anim; Dog dog; Cat cat; Bird bird; animalShout(anim); animalShout(dog); animalShout(cat); animalShout(bird); getchar(); }
在编译之前,函数模板中t.shout()调用的是哪个接口并不确定。在编译期间,编译器推断出模板参数,因此确定调用的shout是哪个具体类型的接口。不同的推断结果调用不同的函数,这就是编译器多态。
2.函数重载
程序在编译之前就知道用哪个函数,即在一个类中有相同的函数名,也就是函数重载,重载函数的参数个数,参数类型或参数顺序三者中必须有一个不同。例子如下:#include<Windows.h> #include<iostream> using namespace std; int Add(int a, int b) { return a + b; } double Add(double a, double b) { return a + b; } float Add(float a, float b) { return a + b; } int main() { cout<<Add(1,2)<<endl; cout<<Add(3.5, 4.5)<<endl; cout << Add(2.22, 3.33) << endl; system("pause"); return 0;
运行时多态
运行时多态,又叫动态多态、晚绑定、覆盖 、重写。运行时多态基于虚函数机制实现多态的功能。在不同但是具有继承关系的类中有相同的函数名,这样的实现方式也叫重写。
运行期多态的设计思想要归结到类继承体系的设计上去。对于有相关功能的对象集合,我们总希望能够抽象出它们共有的功能集合,在基类中将这些功能声明为虚接口(虚函数),然后由子类继承基类去重写这些虚接口,以实现子类特有的具体功能。典型地我们会举下面这个例子:
class Animal { public : virtual void shout() = 0; }; class Dog :public Animal { public: virtual void shout(){ cout << "汪汪!"<<endl; } }; class Cat :public Animal { public: virtual void shout(){ cout << "喵喵~"<<endl; } }; class Bird : public Animal { public: virtual void shout(){ cout << "叽喳!"<<endl; } }; int main() { Animal * anim1 = new Dog; Animal * anim2 = new Cat; Animal * anim3 = new Bird; //藉由指针(或引用)调用的接口,在运行期确定指针(或引用)所指对象的真正类型,调用该类型对应的接口 anim1->shout(); anim2->shout(); anim3->shout(); //delete 对象 ... return 0; }
两种多态的优缺点
运行期多态优点
- OO设计中重要的特性,对客观世界直觉认识。
- 能够处理同一个继承体系下的异质类集合。
运行期多态缺点
- 运行期间进行虚函数绑定,提高了程序运行开销。
- 庞大的类继承层次,对接口的修改易影响类继承层次。
- 由于虚函数在运行期在确定,所以编译器无法对虚函数进行优化。
- 虚表指针增大了对象体积,类也多了一张虚函数表,当然,这是理所应当值得付出的资源消耗,列为缺点有点勉强。
编译期多态优点
- 它带来了泛型编程的概念,使得C++拥有泛型编程与STL这样的强大武器。
- 在编译器完成多态,提高运行期效率。
- 具有很强的适配性与松耦合性,对于特殊类型可由模板偏特化、全特化来处理。
编译期多态缺点
- 程序可读性降低,代码调试带来困难。
- 无法实现模板的分离编译,当工程很大时,编译时间不可小觑。
- 无法处理异质对象集合。
-
Java中编译时多态与运行时多态
2021-04-17 20:12:22运行时多态总结Reference 口诀:成员变量,静态方法看左边;非静态方法:编译看左边,运行看右边 当父类变量引用子类对象时(Father f = new Son();),在这个引用变量f指向的对象中,它的成员变量和静态方法与...
口诀:成员变量,静态方法看左边;非静态方法:编译看左边,运行看右边
当父类变量引用子类对象时(
Father f = new Son();
),在这个引用变量f
指向的对象中,它的成员变量和静态方法与父类是一致的,他的非静态方法,在编译时是与父类一致的,运行时却与子类一致(发生了复写)1. 什么是多态
多态是指允许不同子类型的对象对同一行为作出不同的响应。例如在生活中,比如跑的动作,小猫、小狗和大象,跑起来是不一样的。再比如飞的动作,昆虫、鸟类和飞机,飞起来也 是不一样的。可见,同一行为,通过不同的事物,可以体现出来的不同的形态。多态描述的就是这样的状态。
多态性分为编译时的多态性和运行时的多态性。方法重载(overload)实现的是编译时的多态性(也称为前绑定),而方法重写(override)实现的是运行时的多态性(也称为后绑定)。运行时的多态是面向对象最精髓的东西,要实现运行时多态需要做以下两件事情:
- 方法重写(子类继承父类并重写父类中已有的或抽象的方法)
- 用父类型引用变量引用子类型对象,这样同样的引用调用同样的方法就会根据子类对象的不同而表现出不同的行为
如果在编译时能够确定执行多态方法中的哪一个,称为编译时多态,否则称为运行时多态。
2. 编译时多态
-
方法的重载
方法重载就是在同一个类中,出现了多个同名的方法,他们的参数列表(方法签名)不同 (参数列表的个数不同,参数列表的数据类型不同,参数列表的顺序不同)
根据实际参数的数据类型、个数和次序,Java在编译时能够确定执行重载方法中的哪一个。
-
方法重写时的编译时多态:
除了重载,重写也表现出两种多态性。当一个对象的引用指向的是当前对象所属类的对象时,为编译时多态,其他则为运行时多态。
3. 运行时多态
当父类引用指向子类对象时:
-
父类只能执行那些在父类中声明、被子类覆盖了的子类方法,而不能执行子类新增加的成员方法。在编译时期,首先会去查看父类里面有没有这个方法,如果没有的话向上继续查找,直到找到
Object
类如果还没有的话就报错,如果有的话,到运行阶段,再去看一下子类中有没有覆盖该方法,如果覆盖了,则执行子类覆盖的方法。如果没有则执行父类中原本的方法。 -
当子类和父类有相同属性时,父类还是会执行自己所拥有的属性,若父类中没有的属性子类中有,当父类对象指向子类引用时(向上转型),在编译时期就会报错
-
对于
static
方法还是会执行父类中的方法,这是由于在运行时,虚拟机已经认定static
方法属于哪个类。“重写”只能适用于实例方法,不能用于静态方法。**对于静态方法,只能隐藏,重载,继承。**子类会将父类静态方法的隐藏(hide),但子类的静态方法完全体现不了多态,就像子类属性隐藏父类属性一样,在利用引用访问对象的属性或静态方法时,是引用类型决定了实际上访问的是哪个属性,而非当前引用实际代表的是哪个类。因此,子类静态方法不能覆盖父类的静态方法
/** * @author yzz * @create 2021-04-17 19:57 */ public class PolymorphismTest { public static void main(String[] args) { // 运行时多态 SuperClass clazz = new SubClass(); // 执行的是子类里的方法 clazz.method(); // 执行的是父类中的方法 clazz.method2(); // 子类新增的方法:报错 // clazz.method1(); // 相同属性:调用父类的属性值 System.out.println(clazz.str); // 子类新增属性:报错 // System.out.println(clazz.sonInt); // 静态方法:执行父类中的方法 clazz.method3(); } } // 父类 class SuperClass { static int superInt = 1; String str = "father"; public SuperClass() { System.out.println("父类的构造方法"); } public void method() { System.out.println("父类的method()"); } public void method2() { System.out.println("父类method2()"); } public static void method3() { System.out.println("父类static method3()"); } } // 子类 class SubClass extends SuperClass { static int superInt = 2; String str = "Son"; int sonInt = 1; public SubClass() { System.out.println("子类的构造方法"); } @Override public void method() { System.out.println("子类的method()"); } public void method1() { System.out.println("子类新增方法method1"); } public static void method3() { System.out.println("子类static method3()"); } }
输出:
父类的构造方法 子类的构造方法 子类的method() 父类method2() father 父类static method3()
总结
- 多态是指不同子类型的对象对同一行为作出不同的响应。
- 多态性分为编译时的多态性和运行时的多态性。方法重载实现的是编译时的多态性,而方法重写实现的是运行时的多态性。
- 对于运行时多态,特别注意,父类引用指向子类对象,在调用实例方法时,调用的是子类重写之后的,并且不能调用子类新增的方法,对于属性和static方法来说,还是执行父类原有的
Reference
-
java的编译时多态和运行时多态 | 学步园
2021-02-27 14:16:591、运行时多态和编译时多态的区别?编译时的多态,是指参数列表的不同, 来区分不同的函数, 在编译后, 就自动变成两个不同的函数名. 在运行时谈不上多态运行时多态:用到的是后期绑定的技术, 在程序运行前不知道,会调用...1、运行时多态和编译时多态的区别?
编译时的多态,是指参数列表的不同, 来区分不同的函数, 在编译后, 就自动变成两个不同的函数名. 在运行时谈不上多态
运行时多态:用到的是后期绑定的技术, 在程序运行前不知道,会调用那个方法, 而到运行时, 通过运算程序,动态的算出被调用的地址. 动态调用在继承的时候,方法名 参数列表完全相同时才出现运行时多态!
运行时多态,也就是动态绑定,是指在执行期间(而非编译期间)判断所引用对象的实际类型,根据实际类型判断并调用相应的属性和方法.看看下面这个例子:
abstract class Animal {
private String name;
Animal(String name) {this.name = name;}
/*
public void enjoy(){
System.out.println("叫声......");//父类方法,下面的子类对该方法不满意,重写.
}
*/
public abstract void enjoy();//该方法没有实现的必要(所以我们一般声明为静态方法),但有定义的必要.
}
class Cat extends Animal {
private String eyesColor;
Cat(String n,String c) {super(n); eyesColor = c;}
public void enjoy() {
System.out.println("猫叫声......");
}
//public abstract void enjoy();//如果不想实现父类静态方法,可将此方法声明为静态的,该类也同时为abstract
}
class Dog extends Animal {
private String furColor;
Dog(String n,String c) {super(n); furColor = c;}
public void enjoy() {
System.out.println("狗叫声......");
}
}
class Bird extends Animal {
Bird() {
super("bird");
}
public void enjoy() {
System.out.println("鸟叫声......");
}
}
class Lady {
private String name;
private Animal pet;
Lady(String name,Animal pet) {
this.name = name; this.pet = pet;
}
public void myPetEnjoy(){pet.enjoy();}
}
public class Test {
public static void main(String args[]){
Cat c = new Cat("catname","blue");
Dog d = new Dog("dogname","black");
Bird b = new Bird();
//Lady l1 = new Lady("l1",c);
Lady l2 = new Lady("l2",d);
Lady l3 = new Lady("l3",b);
//l1.myPetEnjoy();
l2.myPetEnjoy();
l3.myPetEnjoy();
}
}
动态绑定的底层实现是指针,我们知道程序中的方法是一段代码,存放在专门的内存区域中(code segment---代码区),当我们在程序执行期间new 出一个对象后调用enjoy方法的时候,JVM动态的把指针指向实际的对象重写的方法,从而实现了动态绑定.
动态绑定的最大好处就是给我们的程序的可扩展性带来了相当大的提高(上面的例子中我们可以继续添加子类或是在main方法中new lady,),如果没有动态绑定,我们一般情况下的做法是在子类中用instanceof判断一个对象是不是我们需要的当前具体对象,但当我们定义好多个子类的时候,每次都要判断,现在有了动态绑定,我们不需要再去判断,而是JVM动态给我们指向具体的对象并调用相应的属性和方法.
-
Java中的运行时多态
2021-03-13 13:42:36Java中的多态性Java中的...Java中有两种类型的多态:编译时多态和运行时多态。我们可以通过方法重载和方法重写在Java中执行多态。如果重载Java中的静态方法,则它是编译时多态性的示例。在这里,我们将重点介绍Jav... -
运行时多态和编译时多态
2021-02-26 08:43:42运行时多态:重写就是一种运行时多态。只有在运行过程中才能清楚调用的是具体的那个方法。重写的情况:public class Dog {public void bark(){System.out.println("woof ");}private static class Hound extends Dog... -
java多态 运行时多态和编译时多态
2021-04-23 19:43:16java多态 运行时多态和编译时多态我们知道java的多态是一个重要的特性,其中体现java的多态有两种形式。运行时的多态和编译时的多态。编译时的多态会发生在方法重载的时候,方法的重载指方法名相同,方法的参数列表... -
杂谈——编译时多态与运行时多态
2018-12-20 10:32:35其实,这也没有啥好蒙圈的,因为: 重载都是编译时多态,而重写表现出两种多态性,当对象引用本类实例时,为编译时多态,否则为运行时多态。 怎么判定是编译时多态还是运行时多态呢? 如果在编译时能够确定执行... -
c++ 多态 运行时多态和编译时多态_码农子与多态的日常
2020-11-22 23:38:08-码农子的日常-______ 那么,到底什么是多态呢? Sorry放错图了(雾 事实上,多态,而非堕胎or多肽,是c++非常常见的一个名词。 抽象定义:一个函数名关联多种含义的能力。(by Walter Savitch) 详细定义:允许将父类... -
C++运行时多态简单介绍
2021-03-24 20:46:47多态与继承时相辅相成的, 将父类定义为一个抽象类,子类可以通过继承的方式定义自己的类,这就是所谓的继承和多态,多态是在运行时编译的,且右基类指针指向子类对象,不能相反,这样基类指针可以在具体实例化... -
编译时多态和运行时多态
2020-10-09 16:32:49编译时多态和运行时多态 多态分为两种情况:编译时多态和运行时多态。如果在编译时能够确定执行多态方法称为编译时多态,否则称为运行时多态。 一、编译时多态 方法重载都是编译时多态。根据实际参数的数据类型、个... -
C++ 编译时多态和运行时多态
2020-01-07 18:02:41多态多为C++的三大特性之一,我们对此的了解和应用大多停留在类继承层次和运行时阶段。那既然有运行(动态)时阶段,那是否也有静态的多态?有,那就是编译时多态 正文 动态多态 运行时的多态存在于继承类中,... -
Java中的编译时多态和运行时多态有什么区别?
2021-02-26 08:43:48如果我们使用实例方法执行(实现)方法重写和方法重载,则它是运行时(动态)多态性。在动态多态中,方法调用和方法主体之间的绑定是在执行时发生的,这种绑定称为动态绑定或后期绑定。示例classSuperClass{... -
c++ 多态 运行时多态和编译时多态_聊聊面试中的多态问题
2020-11-22 23:38:0701—面向对象编程的特点抽象、封装、继承、多态02—什么是多态 ?在程序中同一符号在不同情况下具有不同...编程中的多态3)同一个类中,对应相同的函数名,却执行不同的函数体,即函数重载,属于编译时的多态。4)派生... -
编译时多态、运行时多态
2018-03-25 21:13:26根据何时确定执行多态方法中的哪一个,多态分为两种情况:编译时多态和运行时多态。如果在编译时能够确定执行多态方法中的哪一个,称为编译时多态,否则称为运行时多态。一、编译时多态 方法重载都是编译时多态。... -
java-面向对象三大特性之多态---编译时多态和运行时多态详解
2019-12-16 12:39:44java面向对象三大特性之多态---编译时多态和运行时多态详解 原创颺灏发布于2019-04-01 22:17:55阅读数 494收藏 展开 一.引言 1.什么是多态? 说到重载和重写,大家可能都知道。它们都是多态性的体现,那么说... -
运行时多态、编译时多态和重载、重写的关系(不区分Java和C#,保证能看懂!)
2021-03-02 11:14:12重载和重写我就不解释了,大家都知道,我现在主要是让大家记住重载是编译时多态,重写是运行时多态这句话。编译时可以理解为“编写”代码;运行时也就是代码执行。好了,进入正题:public void... -
c++ 多态 运行时多态和编译时多态_【C++学习笔记(十七)】之多态的理解
2020-11-22 23:38:14本文章由公号【开发小鸽】发布!欢迎关注!!! 老规矩--妹妹镇楼: 一. 多态 多态是面向对象程序设计语言中数据抽象和继承之外的第三个... 多态的类型 C++支持静态多态(编译时多态)和动态多态(运行时多态)。 ... -
编译时多态与运行时多态的区别
2018-03-24 10:48:32(2)运行时多态/动态联编 指联编在程序运行时动态进行,对函数的调用基于对象的类型。 2区别总结 3代码 (1)编译时多态 1)函数重载 //编译时多态,函数调用与**指针类型**有关。 #incl... -
c++ 多态 运行时多态和编译时多态_C++中的多态
2020-11-22 23:38:10多态性(polymorphism)一词意味着具有多种形式。简而言之,我们可以将多态定义为消息以多种形式显示的能力。...在C++中,多态性主要分为两种类型:编译时多态运行时多态1. 编译时多态:这种类型的多态是通过函数重... -
React的零运行时多态组件定义-React开发
2021-05-27 15:39:59用于React react-polymorphic-types的零运行时多态组件定义用于React Motivation的零运行时多态组件定义作为React-polymorphic-box的后继者,该项目提供了更准确的类型且具有更少的开销。 功能基于as prop的值自动... -
多态的定义为只有在运行的时候才会知道引用变量所指向的具体实例对象,为什么有运行时多态和编译时多态之分...
2021-03-02 11:14:58常见的多态包括参数化多态、Ad-hoc多态和运行时多态:参数化多态可以理解为泛型。在泛型函数中,我们把参数和返回值的类型也当作需要填充的参数,这就造成我们看起来调用了同一个泛型函数,但实际调用的函数并不相同... -
重载(编译期多态),重写(运行时多态)
2021-03-17 16:26:06多态顾名思义,是多种状态,是指方法有多种不同的状态,在编译时或运行时才可以确定具体的状态,这种使程序具有多种状态的技术就叫做多态,在面向对象语言中,接口的多种不同的实现方式即为多态。 -
JAVA 多态(运行时多态和编译时多态)及其内存图解
2018-10-21 19:01:37多态弊端: 前期定义的内容不能使用(调用)后期子类的特有方法(就是多态调用的只能是父类)。但如果是继承子类覆盖了父类方法,多态调用的仍是子类的方法! 多态前提: 1、必须有关系(继承、实现) 2、要有... -
c++多态之 运行时多态与编译时多态
2020-02-21 11:19:18(2)运行时多态/动态联编 指联编在程序运行时动态进行,对函数的调用基于对象的类型。 区别总结 代码 (1)编译时多态 1)函数重载 //编译时多态,函数调用与指针类型有关。 #include using namespace std; cl... -
c++ 多态 运行时多态和编译时多态_软件特攻队|针对C++编译期多态与运行期多态,我有话说...
2020-11-22 23:38:17在C++的面向对象编程中,多态是OO三大特性之一,我们称为运行期多态,也称它为动态多态;但在泛型编程中,多态是基于模板的具现化与函数的重载解析,由于这种多态发生于编译期,所以称它为编译期多态或静态多态。...