java方法调用之多态的补充示例(四)
2016-03-31 16:00
579 查看
前一篇博文 java方法调用之动态调用多态(重写override)的实现原理——方法表(三) 讲了多态的实现原理,这里写一个补充示例。
注意这里引用了成员变量。
执行结果如下所示:
关键的字节码指令如下所示:
这里只是给出了关于多态的字节码指令,前面的博文 由常量池 运行时常量池 String intern方法想到的(二)之class文件及字节码指令 中有讲到 String的+操作符都被优化成了StringBuilder。这里的
从字节码中可以看出,
也就是说:多态只适用于父子类同样签名的方法,而属性是不参与多态的。
注意这里面有私有方法,私有方法不参与继承, 也不会出现在方法表中,因为私有方法是由invokespecial指令调用的。
执行结果如下所示:
这个的字节码指令需要看两个文件。
先看Main方法:
从中可以看到调用的都是BaseClass中的方法。
看看BaseClass中的baseMethod方法:
可以看到print方法使用的是invokevirtual,而priMethod使用的是invokespecial。根据在bc.baseMethod();调用时传递的this指针,print方法会发生多态的选择,而priMethod不会有多态发生。
私有方法不会发生多态选择,只根据静态类型进选择。
结论
方法表存放的只是invokevirtual和invokeinterface调用的方法,不包括invokestatic和invokespecial的静态方法、私有方法、构造器方法和父类方法,当然也不包括成员变量。普通public方法是通过invokevirtual指令调用的。示例一
package org.fan.learn.polymorphism; /** * Created by Administrator on 2016/3/31. */ class Greeting { String intro = "Hello"; String target(){ return "world"; } } public class FrenchGreeting extends Greeting { String intro = "Bonjour"; String target(){ return "le monde"; } public static void main(String[] args){ Greeting english = new Greeting(); Greeting french = new FrenchGreeting(); System.out.println(english.intro + "," + english.target()); System.out.println(french.intro + "," + french.target()); System.out.println(((FrenchGreeting)french).intro + "," + ((FrenchGreeting)french).target()); } }
注意这里引用了成员变量。
执行结果如下所示:
关键的字节码指令如下所示:
//english.intro对应的字节码指令 26: aload_1 //局部变量表的1号slot中存放的就是english 27: getfield #11; //Field Greeting.intro:Ljava/lang/String; //english.target() 38: aload_1 39: invokevirtual #14; //Method Greeting.target:()Ljava/lang/String; //french.intro 对应的字节码指令 61: aload_2 //局部变量表的2号slot中存放的就是french 62: getfield #11; //Field Greeting.intro:Ljava/lang/String; //french.target() 73: aload_2 74: invokevirtual #14; //Method Greeting.target:()Ljava/lang/String; //((FrenchGreeting)french).intro 96: aload_2 97: checkcast #6; //class FrenchGreeting 100: getfield #3; //Field FrenchGreeting.intro:Ljava/lang/String; //((FrenchGreeting)french).target() 111: aload_2 112: checkcast #6; //class FrenchGreeting 115: invokevirtual #17; //Method FrenchGreeting.target:()Ljava/lang/String;
这里只是给出了关于多态的字节码指令,前面的博文 由常量池 运行时常量池 String intern方法想到的(二)之class文件及字节码指令 中有讲到 String的+操作符都被优化成了StringBuilder。这里的
System.out.println(english.intro + "," + english.target());中的+也被优化了。
从字节码中可以看出,
english.intro与
french.intro的字节码指令是一样的;
english.target()与
french.target()的字节码指令也是一样的,调用的都是静态类型的成员变量和方法。但是经过强制类型转换之后,java编译器就会自动调用强制类型转换后的属性和方法。
也就是说:多态只适用于父子类同样签名的方法,而属性是不参与多态的。
示例二
package org.fan.learn.polymorphism; /** * Created by Administrator on 2016/3/30. */ public class BaseChildTest { static class BaseClass { //注意这个是私有方法 private void priMethod() { System.out.println("BaseClass scret"); } public void print() { System.out.println("print_BaseClass"); } public void baseMethod() { print(); priMethod(); } } static class ChildClass extends BaseClass { //注意这个是私有方法,没有override BaseClass中的方法 private void priMethod() { System.out.println("ChildClass scret"); } public void print() { System.out.println("print_ChildClass"); } public void childMethod() { System.out.println("childMethod"); } } public static void main(String[] args) { BaseClass bc = new ChildClass(); bc.print(); bc.baseMethod(); } }
注意这里面有私有方法,私有方法不参与继承, 也不会出现在方法表中,因为私有方法是由invokespecial指令调用的。
执行结果如下所示:
这个的字节码指令需要看两个文件。
javap -verbose -c BaseChildTest javap -verbose -c BaseChildTest$ChildClass javap -verbose -c BaseChildTest$BaseClass
先看Main方法:
public static void main(java.lang.String[]); Code: Stack=2, Locals=2, Args_size=1 0: new #2; //class BaseChildTest$ChildClass 3: dup 4: invokespecial #3; //Method BaseChildTest$ChildClass."<init>":()V 7: astore_1 8: aload_1 9: invokevirtual #4; //Method BaseChildTest$BaseClass.print:()V 12: aload_1 13: invokevirtual #5; //Method BaseChildTest$BaseClass.baseMethod:()V 16: return
从中可以看到调用的都是BaseClass中的方法。
看看BaseClass中的baseMethod方法:
public void baseMethod(); Code: Stack=1, Locals=1, Args_size=1 0: aload_0 1: invokevirtual #6; //Method print:()V 4: aload_0 5: invokespecial #7; //Method priMethod:()V 8: return
可以看到print方法使用的是invokevirtual,而priMethod使用的是invokespecial。根据在bc.baseMethod();调用时传递的this指针,print方法会发生多态的选择,而priMethod不会有多态发生。
结束语
成员变量的访问只根据静态类型进行选择。私有方法不会发生多态选择,只根据静态类型进选择。
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- c++11 + SDL2 + ffmpeg +OpenAL + java = Android播放器
- 插入排序
- 冒泡排序
- 堆排序
- 快速排序
- 二叉查找树