- 浏览: 182601 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
grzrt:
zkf55915 写道哥们怎么用啊
好久不用了,就是看帮助资 ...
淘宝MetaQ开源消息队列安装 -
zkf55915:
哥们怎么用啊
淘宝MetaQ开源消息队列安装 -
grzrt:
jinnianshilongnian 写道整这个了?
没有 看 ...
linux内核中链表的实现 -
jinnianshilongnian:
整这个了?
linux内核中链表的实现
JAVA中的继承分析
- 博客分类:
- JAVA
为什么写这篇博客,之前对继承的理解知识大体理论上,最近有个同事问了个问题,发现对JAVA继承的底层实现相当模糊,结合《深入理解Java虚拟机:JVM高级特性与最佳实践》以及上网查的资料进行了一下深入学习。
程序:现在又两个父子类如下
class Parent{ public String str = "Parent"; private int a = 10; public int getA() { return a; } } class Chield extends Parent { public String str = "Chield"; private int a = 20; public int getA() { return a; } }
测试程序1:
public class TestInherit { public static void main(String[] args) { Parent p1 = new Parent(); Parent c1 = new Chield(); TestInherit.sayInherit(p1); TestInherit.sayInherit(c1); Parent p2 = new Parent(); Chield c2 = new Chield(); TestInherit.sayInherit(p2); TestInherit.sayInherit(c2); } public static void sayInherit(Parent p) { System.out.println("Call Parent"); } public static void sayInherit(Chield c) { System.out.println("Call Chield"); } }
结果是:
Call Parent
Call Parent
Call Parent
Call Chield
首先介绍方法调用的四条字节码指令:
invokevirtual 调用对象的实例方法,根据对象的实际类型进行分配,
invokeinterface 调用由接口实现的方法,在运行时对象中找到相应的实现;
invokespecial 调用需要特殊处理的实例方法,即实例的初始化<init>、private方法或超类的方法;
invokestatic 调用静态方法(static方法)。
其余字节码操作指令不作介绍。
代码:
Parent c1 = new Chield();
中Parent 称为静态类型,Chield称为实际类型。
静态绑定:如果是private,static或者final方法或者构造器,那么编译时就可以准备知道应该调用哪个方法,这种调用方式成为静态绑定。对应的字节码指令是:invokespecila,invokestatic(应用:overload,由于发生在编译期所以voreload不是由虚拟机来执行的)
动态绑定:与静态绑定相对,方法调用在运行时才能决定的,就是动态绑定。对应的指令为:invokevirtual(应用:override)
invokevirtual指令的运行时解析过程大致如下:
1)找到操作数栈顶的第一个元素所指向的对象的实际类型, 记作C
2)若果在类型C中找到常量中的描述符和简单名称都相符的方法,则进行访问权限校验,如果通过则返回这个方法的直接引用,查找过程结束,不通过则返回java.lang.IllegalAccessError异常,
3)否则,按照继承关系从下到上依次对C的各个父类进行第2步的搜索和验证,
4)如果始终没找到合适的方法,则抛出java.lang.AbstractMethodError异常。
上边测试程序的子节码如下:
public class com.rt.TestInherit extends java.lang.Object{
public com.rt.TestInherit();
public static void main(java.lang.String[]);
Code:
0: new #16; //class com/rt/Parent
3: dup
4: invokespecial #18; //Method com/rt/Parent."<init>":()V #初始化
7: astore_1 #局部变量表 索引为1的位置
8: new #19; //class com/rt/Chield
11: dup
12: invokespecial #21; //Method com/rt/Chield."<init>":()V #初始化
15: astore_2 #局部变量表 索引为1的位置
16: aload_1 #加载局部变量表 索引为1的位置reference类型值到 操作数栈
17: invokestatic #22; //Method sayInherit:(Lcom/rt/Parent;)V #采用静态绑定
20: aload_2 #加载局部变量表 索引为2的位置reference类型值到 操作数栈
#采用静态绑定
,所以虽然c1变量的实际类型是Chiled,由于采用静态绑定方法参数是静态类型,因此输出“Call Parent”
21: invokestatic #22; //Method sayInherit:(Lcom/rt/Parent;)V
24: new #16; //class com/rt/Parent
27: dup
28: invokespecial #18; //Method com/rt/Parent."<init>":()V
31: astore_3
32: new #19; //class com/rt/Chield
35: dup
36: invokespecial #21; //Method com/rt/Chield."<init>":()V
39: astore 4
41: aload_3
42: invokestatic #22; //Method sayInherit:(Lcom/rt/Parent;)V
45: aload 4
47: invokestatic #26; //Method sayInherit:(Lcom/rt/Chield;)V
50: return
public static void sayInherit(com.rt.Parent);
Code:
0: getstatic #37; //Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #43; //String Call Parent
5: invokevirtual #45; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
public static void sayInherit(com.rt.Chield);
Code:
0: getstatic #37; //Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #52; //String Call Chield
5: invokevirtual #45; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
}
主要疑点在红色标记处。
测试程序2:
public class TestInherit { public static void main(String[] args) { Parent p1 = new Parent(); Parent c1 = new Chield(); System.out.println(p1.str); System.out.println(c1.str); System.out.println(p1.getA()); System.out.println(c1.getA()); } }
输出结果:
Parent
Parent
10
20
在Eclipse中,通过Debug查看c1中的属性如下图:
可以看出,子类中包含所有父类中的属性,这是由于在加载的时候会先加载父类。
System.out.println(p1.str);
System.out.println(c1.str);
对应字节码如下:
19: aload_1 #从局部变量表中加载父类到操作数栈 20: getfield #28; //Field com/rt/Parent.str:Ljava/lang/String; 23: invokevirtual #32; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 26: getstatic #22; //Field java/lang/System.out:Ljava/io/PrintStream; 29: aload_2 #从局部变量表中加载子类类到操作数栈 30: getfield #28; //Field com/rt/Parent.str:Ljava/lang/String; #调用invokevirtual指令,会采用动态分配,找到实际类型子类对象(new Chield()生成) #但是由于属性是静态绑定,所以导致输出的父类的属性 #如果调用的是方法,那么就会通过动态类型绑定到子类对象上 33: invokevirtual #32; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 36: getstatic #22; //Field java/lang/System.out:Ljava/io/PrintStream;
原因是:在Java中,属性绑定到类型,方法绑定到对象!
发表评论
-
项目代码质量控制
2014-10-20 17:15 781在以后的开发项目时可以适当使用工具进行程序检查: 1、F ... -
WorkbookFactory 找不到
2013-11-08 10:46 916在最近的POI版本中,poi-3.9.jar包中找不到Work ... -
记一次JVM GC日志分析
2013-03-08 21:36 1708这几天在准备升级JDK版本到1.6,对目前线上JVM(版 ... -
Eclipse 相同变量的高亮 及颜色
2013-02-18 17:26 1583在Eclipse/MyEclipse中如果不小心把变量的高 ... -
java jstack dump 线程 介绍 解释
2013-02-05 15:52 1168hi,all: 最近抽时间把JVM运行 ... -
[转载]JDMK 基本JMX配置( html adaptor)
2013-01-07 13:37 1651原文地址: JDMK 基本JMX配置( html adap ... -
JVM学习之:虚拟机中的运行时栈帧总结(二)
2012-12-12 19:46 796在 JVM学习之:虚拟机 ... -
JVM学习之:虚拟机中的运行时栈帧总结(一)
2012-12-12 19:45 817每 个人都知道,各种各样的动画视频,都是由一帧一帧图片连 ... -
JAVA字符串占位符
2012-12-06 08:24 3175包 java.text.MessageFormat java ... -
copy项目是容易出现的错误--webAppRootKey错误
2012-12-05 21:18 686Tomcat 发布多个项目时抛的webAppRootKey错误 ... -
web.xml配置总结
2012-12-05 20:50 627一、关于webAppRootKey的定义 默 ... -
spring组件扫描<context:component-scan/>使用详解
2012-12-05 19:14 696关于spring自动检测组件的使用方式网上太多了,而且也不 ... -
spring组件扫描<context:component-scan/>使用详解 (
2012-11-28 08:57 665关于spring自动检测组件的使用方式网上太多了,而且也不 ... -
static class 静态类(Java)
2012-11-23 20:20 815一般情况下是不可以用static 修饰类的。 ... -
java jvm 调优实战
2012-11-13 10:01 7701.eclipse 打印gc日志 eclipse根目录 ... -
Zookeeper的一致性协议:Zab
2012-11-04 16:14 1164Zookeeper使用了一种称为 ... -
浅谈java内存模型
2012-10-30 19:29 756不同的平台,内存模 ... -
JVM分代垃圾回收策略的基础概念
2012-08-15 12:43 662由于不同对象的生命周期不一样,因此在JVM的垃圾回收策略中有分 ... -
bloom filter 的Java 版
2012-07-26 21:50 846属于转贴:http://www.cnblo ... -
JAVA 条件表达式 陷阱
2012-07-25 18:34 1235代码: Map<String, Integer& ...
相关推荐
想要下载此文件,请先下载本人“java程序中的内存分配问题”,因为那个例子比较简单而且分析详细透彻,可以使你更容易理解,如果你对java程序执行过程中的内存分配有一定的了解,可以直接下载本文件
刚开始学,需要简单题目加深对概念的理解
Java语言继承中多态的机理分析.pdf
java 实验 继承与多态rectAngle 定义矩形类,用户输入矩形的长与宽,程序计算其面积和周长;派生子类正方形类,定义一个接口Printable源代码
主要介绍了java中继承测试代码分析,具有一定借鉴价值,需要的朋友可以参考下。
Java内部类继承问题的分析
用到了java中方法的重写、重载、数组的相关操作,实现了教师、学生信息的录入、储存、人数统计、输出、删除等功能,缺失统计不同系不同班级学生成绩的功能,尽量有时间补上,程序很简单,仅仅是老师布置的实验题。...
(1)Java不支持多继承,也是说子类至多只能有一个父类。 (2)子类继承了其父类中不是私有的成员变量和成员方法,作为自己的成员变量和方法。 (3)子类中定义的成员变量和父类中定义的成员变量相同时,...
主要介绍了Java 继承原理与用法,结合实例形式分析了java面向对象程序设计中继承的概念、原理、用法及操作注意事项,需要的朋友可以参考下
主要介绍了Java类的继承原理与用法,结合实例形式分析了java类的继承相关原理、使用方法及操作注意事项,需要的朋友可以参考下
这个库的目的是要在java中提供一个类似parsec, spirit的库,这种组合子库并非c++的专利,java/c#也可以做到。这个库还将在java5.0上被改写,类型安全上它将也不再逊色于c++。 那么,为什么叫“函数式”呢?java是...
主要介绍了浅谈Java继承中的转型及其内存分配,首先分享了简单的代码及运行结果,然后对其进行分析,继而引出了
本专栏主要为Java程序设计(基础)实验报告和Java程序设计(进阶)实验报告,基础篇有JAVA环境搭建、Java语言基础、方法和数组、面向对象基础、Java常用类、继承与接口、成员访问控制与异常、JavaFX程序设计、Java...
主要介绍了java的继承原理与实现方法,结合实例形式详细分析了Java继承的概念、原理、用法及相关操作注意事项,需要的朋友可以参考下
2.在我设计的解释器中,我以语义分析接口作为整个程序的入口(实现语义分析的代码块继承了语法分析的代码块,同时采用“语法制导翻译”方法,这样就能做到两个过程合为一个阶段,即在语法分析的过程中,执行语义分析)...
本文将介绍组合和继承的概念及区别,并从多方面分析在写代码时如何进行选择。文中通过示例代码介绍的很详细,有需要的朋友可以参考借鉴,下面来一起看看吧。
主要介绍了Java中final与继承操作,结合实例形式分析了Java中使用final阻止继承的相关原理与操作注意事项,需要的朋友可以参考下
主要介绍了java中的多态和继承,结合实例形式分析了java中的多态和继承原理、实现方法及相关操作注意事项,需要的朋友可以参考下
主要介绍了Java泛型的继承和实现操作,结合实例形式分析了java泛型类的继承以及泛型接口的实现相关操作技巧,需要的朋友可以参考下
主要介绍了Java继承的实现与继承限制,结合具体实例形式分析了Java继承的定义、实现以及继承的相关限制,需要的朋友可以参考下