- 浏览: 187779 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
grzrt:
zkf55915 写道哥们怎么用啊
好久不用了,就是看帮助资 ...
淘宝MetaQ开源消息队列安装 -
zkf55915:
哥们怎么用啊
淘宝MetaQ开源消息队列安装 -
grzrt:
jinnianshilongnian 写道整这个了?
没有 看 ...
linux内核中链表的实现 -
jinnianshilongnian:
整这个了?
linux内核中链表的实现
为什么写这篇博客,之前对继承的理解知识大体理论上,最近有个同事问了个问题,发现对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 829在以后的开发项目时可以适当使用工具进行程序检查: 1、F ... -
WorkbookFactory 找不到
2013-11-08 10:46 994在最近的POI版本中,poi-3.9.jar包中找不到Work ... -
记一次JVM GC日志分析
2013-03-08 21:36 1748这几天在准备升级JDK版本到1.6,对目前线上JVM(版 ... -
Eclipse 相同变量的高亮 及颜色
2013-02-18 17:26 1646在Eclipse/MyEclipse中如果不小心把变量的高 ... -
java jstack dump 线程 介绍 解释
2013-02-05 15:52 1212hi,all: 最近抽时间把JVM运行 ... -
[转载]JDMK 基本JMX配置( html adaptor)
2013-01-07 13:37 1728原文地址: JDMK 基本JMX配置( html adap ... -
JVM学习之:虚拟机中的运行时栈帧总结(二)
2012-12-12 19:46 839在 JVM学习之:虚拟机 ... -
JVM学习之:虚拟机中的运行时栈帧总结(一)
2012-12-12 19:45 868每 个人都知道,各种各样的动画视频,都是由一帧一帧图片连 ... -
JAVA字符串占位符
2012-12-06 08:24 3220包 java.text.MessageFormat java ... -
copy项目是容易出现的错误--webAppRootKey错误
2012-12-05 21:18 727Tomcat 发布多个项目时抛的webAppRootKey错误 ... -
web.xml配置总结
2012-12-05 20:50 665一、关于webAppRootKey的定义 默 ... -
spring组件扫描<context:component-scan/>使用详解
2012-12-05 19:14 730关于spring自动检测组件的使用方式网上太多了,而且也不 ... -
spring组件扫描<context:component-scan/>使用详解 (
2012-11-28 08:57 716关于spring自动检测组件的使用方式网上太多了,而且也不 ... -
static class 静态类(Java)
2012-11-23 20:20 872一般情况下是不可以用static 修饰类的。 ... -
java jvm 调优实战
2012-11-13 10:01 8111.eclipse 打印gc日志 eclipse根目录 ... -
Zookeeper的一致性协议:Zab
2012-11-04 16:14 1225Zookeeper使用了一种称为 ... -
浅谈java内存模型
2012-10-30 19:29 836不同的平台,内存模 ... -
JVM分代垃圾回收策略的基础概念
2012-08-15 12:43 698由于不同对象的生命周期不一样,因此在JVM的垃圾回收策略中有分 ... -
bloom filter 的Java 版
2012-07-26 21:50 884属于转贴:http://www.cnblo ... -
JAVA 条件表达式 陷阱
2012-07-25 18:34 1279代码: Map<String, Integer& ...
相关推荐
当我们谈论“java中与继承有关的程序内存分析”时,主要关注的是在Java程序运行时,内存是如何为继承体系的实例分配的。 Java内存主要分为三个区域:栈(Stack)、堆(Heap)和方法区(Method Area)。在讨论继承时...
1. **类的继承**:在Java中,继承是面向对象编程的重要特性,允许一个类(子类)继承另一个类(父类)的属性和方法。例如,我们可以创建一个`Music`类作为其他音乐相关类的基类。 2. **构造方法**:构造方法用于...
"Java语言继承中多态的机理分析" Java语言继承中多态的机理分析是面向对象程序设计的主要特征之一。在Java语言中,继承是指一个类继承另一个类的所有非私有成员变量和方法,并添加自己特有的成员变量和方法,从而...
Java 中继承测试代码分析 Java 中继承测试代码分析是 Java 编程语言中的一种重要概念。继承是基于已经存在的类构造一个新类,可以复用这些类的方法和域。在 Java 中,继承关系的指定是通过关键字 "extends" 实现的...
在这个"Java继承实例源代码"的压缩包中,包含的文件可能提供了关于Java继承和多态性的实际应用示例。 首先,我们来看“继承”这一概念。在Java中,通过使用关键字`extends`,一个类可以声明其为另一个类的子类。...
在深入探讨Java中多态的内存分析之前,我们需要先理解一些基本概念。 首先,了解Java内存模型至关重要。Java程序运行时主要涉及四种内存区域:程序计数器、虚拟机栈、本地方法栈、堆和方法区(在Java 8及以后版本中...
Java继承和多态的程序设计 本节课我们将学习使用Java语言编写的有关继承和多态的程序设计。这个程序旨在帮助初学者更好地理解Java中的继承和多态机制。 继承是Java语言中的一种机制,它允许一个类继承另一个类的...
### Java继承与多态知识点详解 #### 一、引言 在面向对象编程语言中,继承和多态是非常重要的概念。它们提供了强大的机制来管理代码的复杂性,并且能够有效地复用现有代码。本文将详细介绍Java中的继承和多态概念...
java 实验 继承与多态rectAngle 定义矩形类,用户输入矩形的长与宽,程序计算其面积和周长;派生子类正方形类,定义一个接口Printable源代码
JAVA子类与继承实验报告 实验1 中国人与美国人 实验2 面积之和
在Java编程语言中,继承是面向对象编程的一个核心概念,它允许我们定义类的层次结构,使得一个类可以从另一个类那里继承属性和方法。通过继承,我们可以创建更加具体和专用的类,同时避免代码重复,提高代码的复用性...
### 论JAVA继承机制中父类与子类的关系 #### 摘要 本文深入探讨了Java语言中的继承机制,并重点分析了父类与子类之间的关系。文章围绕子类继承父类成员的过程、成员变量及方法的赋值、重写、覆盖等问题展开讨论,...
下面我们将深入探讨Java在决策分析中的应用,并结合书中的经典案例进行解析。 首先,决策分析的核心在于数据处理。在Java中,我们可以使用内置的集合框架,如ArrayList、LinkedList、HashMap等,来存储和管理数据。...
下面将对Java继承的基本概念、语法格式、继承关系、方法重写、自动转型等进行详细的总结和分析。 一、继承的基本概念 继承是特殊的is-a关系,即子类继承父类,说明子类是一种特殊的父类,并且具有父类所不具有的...
Java内部类继承问题的分析主要关注的是在Java编程中,当内部类(也称为嵌套类)参与继承时所面临的挑战和潜在问题。Java语言采用了单一继承机制,即一个类只能从一个父类继承,这有助于提高代码的可读性和可维护性。...
在Java编程语言中,继承是面向对象编程的一个核心特性,它允许一个类(子类)继承另一个类(父类...这个“java继承代码”示例为你提供了一个实践这些概念的机会,通过阅读和分析代码,你可以更好地理解Java的继承机制。
面向对象抽象和Java继承机制是现代软件开发中不可或缺的部分。通过抽象,我们可以将复杂的问题分解为更小、更易于管理的部分;而通过继承,我们可以复用现有的代码,并且更容易地扩展和维护我们的程序。理解和熟练...
排序算法是Java算法分析中的重要部分。Java标准库提供了多种排序算法实现,如Arrays.sort()内部采用的快速排序和归并排序,以及Collections.sort()默认使用的TimSort。理解这些排序算法的原理,有助于在实际开发中...
在Java编程语言中,类的继承是面向对象编程的一个核心概念。它允许我们创建一个新类,该类基于已存在的类(称为父类或超类),并在此基础上添加新的功能或者修改现有功能。通过继承,我们可以实现代码的重用,减少...