在Java源文件编译为Class文件时,并不包含传统编译中的“连接”步骤。即一切方法调用在Class文件中都只是符号引用,而不是真正的指向方法在实际运行内存布局中的入口地址(相当于类加载过程中“解析”步骤中的直接引用)。因此才给Java带来强大的动态拓展能力,但也使Java的方法调用过程变得复杂,需要类在加载期间甚至在运行期间才能确定调用目标方法的直接引用。
方法调用过程包括以下几个步骤:
解析
因为所有的方法调用的目标方法在Class文件中都是一个常量池中的符号引用,在类加载的解析阶段,这些符号引用中的一部分会被翻译为直接引用。这种解析能够成立的前提是:方法在程序真正运行之前就有一个可确定的执行版本(也就是具体哪一个方法),并且这个方法在程序运行过程中不会被改变。换句话说,调用目标在程序代码写好、编译器进行编译时就已经能够确定下来。这类方法的调用称为“解析”。
Java语言中符合“编译期可知,运行时期不可变”要求的方法主要有静态方法和私有方法两大类,前者直接与类型关联,后者由于外部不可访问,所以这两种方法都不可能通过继承或者别的方式重写出其他版本,因此他们都适合在编译期进行解析。
Java虚拟机中提供了4条方法调用字节码指令(这里是jdk1.6标准)
- invokestatic:调用静态方法。
- invokespecial:调用实例构造器<init>方法、私有方法和父类方法。
- invokevirtual:调用所有虚方法。
- invokeinterface:调用接口方法,会在运行时再确定一个实现此接口的对象。
只要能被invokestatic和invokespecial指令调用的方法,都可以在解析阶段确定唯一版本,符合这个条件的有静态方法,私有方法,构造器和父类方法。它们在类加载的时候就会把符号引用解析为该方法的直接引用。这些方法也称作“非虚方法”,与之相反的方法(除了final修饰过的)被称为虚方法。
解析调用一定是一个静态过程,在编译期间就可以完全确定。
分派
静态分派
静态分派主要是牵涉到类的重载(Overload)。在说明重载问题之前,先按如下代码定义两个重要的概念:
Animal rabbit = new Rabbit();
在上述代码中,“Animal ”被称为变量的静态类型(Static Type)或者外观类型(Apparent Type),后面的“Rabbit”被称为变量的实际类型(Actual Type)。静态类型是编译期可知的,而实际类型在运行期才可以确定。使用哪个重载版本,完全取决于传入参量的数量和数据类型。编译器在重载时是通过参数的静态类型而不是实际类型作为判定依据。而由于静态类型是不会变化的,所以,在编译阶段就已经明确了要调用哪个方法版本。
静态分派选择的重载版本往往并不是唯一的,只能确定一个“更加合适”的版本。产生这种模糊结论的原因是因为字面量不需要定义,所以字面量没有显式的静态类型,它的静态类型只能通过语言上的规则去理解和推断。
动态分派
它是多态性的另一个重要体现——重写(Override)。在运行期根据变量的实际类型来确定方法执行的版本。虚拟机在实现动态分派时采用的方法是,在类的方法区中建立一个“虚方法表”。虚方法表中存放着各个方法的实际入口地址,如果某个方法在子类中没有被重写,那么子类的虚方法表里面的入口地址就和父类相同方法的地址入口是一致的。如果子类重写了父类方法,子类方法表中的地址会被替换为指向子类实现版本的入口地址。
相关推荐
综上所述,基于虚拟机字节码注入的动态权限控制系统是一种有效应对Android应用安全挑战的方法。它不仅能够解决现有的安全问题,还具备一定的前瞻性,能够适应未来可能出现的新威胁。此外,该方案的优势在于其实现...
本文提出了一种可对Java字节码进行并行执行的方法,即通过分析依赖关系图,确定哪些指令可以并行执行,然后将这些指令分配到不同的处理器上执行,从而提高Java字节码执行的效率。 五、结论 本文对Java字节码执行的...
### 探索Java虚拟机的心脏:字节码执行全解析 #### Java语言概览 Java自1995年由Sun Microsystems(现归Oracle所有)发布以来,已成为全球范围内广泛应用的编程语言。作为一种面向对象的语言,Java将现实世界中的...
总的来说,理解Java字节码有助于深入洞察JVM的工作原理,包括内存管理、方法调用的细节以及异常处理的实现。这对于优化代码性能、分析和调试程序以及编写更高效的Java代码都至关重要。通过研究字节码,开发者可以更...
总结起来,Java虚拟机的字节码指令集是执行Java代码的基础,它包含了数据操作、流程控制、对象操作、方法调用等各个方面,确保了Java程序的跨平台性和高效执行。理解和掌握这些指令对于深入理解Java的运行机制至关...
这涉及到对JVM的理解,包括其内部工作原理、字节码解析、类加载机制以及方法调用等核心概念。以下是一些关于Java虚拟机开发的相关知识点: 1. **Java虚拟机结构**:JVM是Java平台的核心组成部分,它负责执行Java...
理解Java字节码有助于优化程序性能,例如,通过查看字节码可以分析方法的调用频率,为JIT编译提供依据;或者通过修改字节码实现代码注入,进行调试或增强功能。 总的来说,Java字节码是Java平台的核心组成部分,它...
Dalvik字节码是一种栈式架构,每个方法由一系列的指令组成,这些指令在运行时被解释执行。每个指令占据一个字节,并且可能带有附加的操作数。Dalvik字节码的设计是为了在资源受限的移动设备上高效运行。 在Android...
Java虚拟机(JVM)是一种能够执行Java字节码的虚拟机,它提供了一个平台无关的执行环境,使得Java程序可以在各种不同的硬件和操作系统上运行。JVM解释执行机制是Java虚拟机执行字节码的一种方式,其中解释器将Java...
Java 编译器不将对变量和方法的引用编译为数值引用,也不确定程序执行过程中的内存布局,而是将这些符号引用信息保留在字节码中,由解释器在运行过程中创立内存布局,然后再通过查表来确定一个方法所在的地址。...
在运行时,每个Java线程都对应一个独立的虚拟机执行引擎实例,从线程启动到结束,它一直在执行字节码或本地方法。除了用户程序的线程,JVM实现还可能包含一些后台线程,如垃圾收集器,这些线程不需要直接对应执行...
Javaagent技术允许我们在JVM启动时附加一个代理程序,这个代理可以修改类的字节码,从而在不改变原有代码的情况下,实现对方法调用的拦截和处理。 字节码编程不仅是Java开发者的必备技能之一,它也是深入理解JVM...
例如,为了在方法执行前后添加日志,我们可以插入`System.out.println`的字节码。 5. **结束方法和类**:当所有增强完成,调用`visitEnd`结束方法和`visitEnd`结束类的定义。 6. **生成字节码并加载到JVM**:最后...
比如,在处理数组、循环、条件判断以及函数调用等操作时,字节码中的每个指令都对应着相应的操作,包括加载常量、执行算术运算、调用函数、返回结果等。 符号解析功能则让开发者能够更加直观地理解代码逻辑。在Lua...
在使用这类编辑器时,用户需要对Java虚拟机(JVM)的指令集有一定的了解,因为字节码本质上就是JVM可执行的二进制指令。 Java字节码是由一系列16进制数字组成的,每个字节对应一个或多个JVM指令。这些指令控制着JVM...
4. 在方法的字节码流中,使用`visitInsn`系列方法插入特定的字节码指令,实现对原方法调用的包装。 5. 使用`ClassWriter`生成字节码并将其转换为`byte[]`数组。 6. 最后,通过`ClassLoader`将生成的字节码加载为...
操作码决定了虚拟机执行的动作,如加载常量、调用方法、分配对象等。这种紧凑的设计使得Dalvik能够快速解析和执行代码。 3. **Dalvik操作码体系** Dalvik虚拟机的操作码分为几个大类:数据操作、控制转移、类型...
在Java中,源代码被编译成字节码,这是一种中间语言,由Java虚拟机(JVM)执行。然而,有时我们需要查看这些字节码以进行调试、逆向工程或学习目的,这时就需要用到字节码反编译工具,如`jd-gui`。 `jd-gui`是一款...