Java 编译时多态和运行时多态
2016-05-02 11:36
393 查看
根据何时确定执行多态方法中的哪一个,多态分为两种情况:编译时多态和运行时多态。如果在编译时能够确定执行多态方法
中的哪一个,称为编译时多态,否则称为运行时多态。
一、编译时多态
方法重载都是编译时多态。根据实际参数的数据类型、个数和次序,Java在编译时能够确定执行重载方法中的哪一个。
方法覆盖表现出两种多态性,当对象引用本类实例时,为编译时多态,否则为运行时多态。例如,以下声明p、m引用本类实
例,调用toString()方法是编译时多态。
二、运行时多态
1.当以下父类对象p引用子类实例时,p.toString)执行谁的setName()方法?
Java支持运行时多态,意为p.toString()实际执行p所引用实例的toString(),究竟执行Person类还是Man类的方法,运行时再
确定。如果Man类声明了toString()方法,则执行之;否则执行Person类的toString()方法。
程序运行时,Java从实例所属的类开始寻找匹配的方法执行,如果当前类中没有匹配的方法,则沿着继承关系逐层向上,依次
在父类或各祖先类中寻找匹配方法,直到Object类。寻找p.toString()匹配执行方法的过程如下图所示。
因此,父类对象只能执行那些在父类中声明、被子类覆盖了的子类方法,如toString(),不能执行子类增加的成员方法。
2.将上述例子中toString方法改为getName,因为在Object类中有toString类,无法测试Person与Man中所匹配的执行方法。
此例中Person类型要引用Man类的实例,因Person中未定义setName()方法,故需要把Person类显式地转换为Man类,然后调用
Man中的getName方法。
3.将例子1中Person和Man的方法名改为静态的getName()方法,会返回什么结果呢?
栗子中子类Man隐藏父类Person的属性,而 Person p = new Man() 表示“先声明一个Person类的对象p,然后用Man类对
p进行实例化”,即引用类型为Person类,实际代表的是Man类。因此,访问的是Person的属性及静态方法,详细解释如下。
所谓静态,就是在运行时,虚拟机已经认定此方法属于哪个类。“重写”只能适用于实例方法,不能用于静态方法。对于静态
方法,只能隐藏,重载,继承。
子类对于父类静态方法的隐藏(hide),子类的静态方法完全体现不了多态,就像子类属性隐藏父类属性一样,在利用引用访问
对象的属性或静态方法时,是引用类型决定了实际上访问的是哪个属性,而非当前引用实际代表的是哪个类。因此,子类静态方法
不能覆盖父类的静态方法。
父类中属性只能被隐藏,而不能被覆盖;而对于方法来说,方法隐藏只有一种形式,就是父类和子类存在相同的静态方法。
参考文献:
Java程序设计实用教程
中的哪一个,称为编译时多态,否则称为运行时多态。
一、编译时多态
方法重载都是编译时多态。根据实际参数的数据类型、个数和次序,Java在编译时能够确定执行重载方法中的哪一个。
方法覆盖表现出两种多态性,当对象引用本类实例时,为编译时多态,否则为运行时多态。例如,以下声明p、m引用本类实
例,调用toString()方法是编译时多态。
public class Test { public static void main(String[] args) { Person p = new Person(); //对象引用本类实例 Man m = new Man(); //编译时多态,执行Person类的toString() System.out.println(p.toString()); System.out.println(m.toString()); //编译时多态,执行Man类的toString() } } class Person{ public String toString() { String name = "Person"; return name; } } class Man extends Person{ public String toString(){ String name = "Man"; return name; } }
二、运行时多态
1.当以下父类对象p引用子类实例时,p.toString)执行谁的setName()方法?
Person p = new Man(); p.toString();
Java支持运行时多态,意为p.toString()实际执行p所引用实例的toString(),究竟执行Person类还是Man类的方法,运行时再
确定。如果Man类声明了toString()方法,则执行之;否则执行Person类的toString()方法。
程序运行时,Java从实例所属的类开始寻找匹配的方法执行,如果当前类中没有匹配的方法,则沿着继承关系逐层向上,依次
在父类或各祖先类中寻找匹配方法,直到Object类。寻找p.toString()匹配执行方法的过程如下图所示。
因此,父类对象只能执行那些在父类中声明、被子类覆盖了的子类方法,如toString(),不能执行子类增加的成员方法。
2.将上述例子中toString方法改为getName,因为在Object类中有toString类,无法测试Person与Man中所匹配的执行方法。
public class Test { //例子2 public static void main(String[] args) { Person p = new Man(); System.out.println(((Man) p).getName()); //返回结果为Man } } class Person{} class Man extends Person{ public String getName(){ String name = "Man"; return name; } }
此例中Person类型要引用Man类的实例,因Person中未定义setName()方法,故需要把Person类显式地转换为Man类,然后调用
Man中的getName方法。
3.将例子1中Person和Man的方法名改为静态的getName()方法,会返回什么结果呢?
public class Test { //例子3 public static void main(String[] args) { Person p = new Man(); System.out.println(p.type); //返回结果为P System.out.println(p.getName()); //返回结果为Person } } class Person{ String type = "P"; public static String getName() { String name = "Person"; return name; } } class Man extends Person{ String type = "M"; public static String getName(){ String name = "Man"; return name; } }
栗子中子类Man隐藏父类Person的属性,而 Person p = new Man() 表示“先声明一个Person类的对象p,然后用Man类对
p进行实例化”,即引用类型为Person类,实际代表的是Man类。因此,访问的是Person的属性及静态方法,详细解释如下。
所谓静态,就是在运行时,虚拟机已经认定此方法属于哪个类。“重写”只能适用于实例方法,不能用于静态方法。对于静态
方法,只能隐藏,重载,继承。
子类对于父类静态方法的隐藏(hide),子类的静态方法完全体现不了多态,就像子类属性隐藏父类属性一样,在利用引用访问
对象的属性或静态方法时,是引用类型决定了实际上访问的是哪个属性,而非当前引用实际代表的是哪个类。因此,子类静态方法
不能覆盖父类的静态方法。
父类中属性只能被隐藏,而不能被覆盖;而对于方法来说,方法隐藏只有一种形式,就是父类和子类存在相同的静态方法。
参考文献:
Java程序设计实用教程
相关文章推荐
- Loadrunner中java Vuser协议脚本开发
- Hibernate hbm2java meta标签学习
- java学习-数组2
- 移位操作符
- 用Java写解谜RPG-3.MVC下的开始界面和所谓按钮
- java 实际场景下根节点 叶子节点 的不处理方法
- Java中的基础----JVM加载class文件的原理
- Java中String
- Java中String
- JAVA技术发展——你不知道的J2SE(三)
- Spring NamedParameterJdbcTemplate 详解
- java中将对象写入文件
- java多态性理解
- JAVAACRIPT基础教程(第8版)---第8章_处理事件
- Java数据类型
- 第N次重学Struts2之路(一)
- 【附源码】搭建MVC:Spring+FreeMarker+MyBatis
- 码农小汪-Spring-MVC 控制器4
- 初识java异常处理
- spring cloud/mesos:在mesos上运行高可用的eureka服务发现