最近有空,继续写写jvm的学习笔记。这次写写java中的方法调用过程。
程序在有限的资源下运行当然是越快越好,这就离不开优化。一般来说都是业务逻辑优化(这也是最有效的),说到程序的运行的优化就不得不牵扯到JVM底层的字节码了。查看字节码的方法是javap -c **.class,这里建议 javap -c **.class > **.txt 来保存成文本文件方便用工具查看。
从class生成的字节码来看,JAVA的方法调用分为4种: invokestatic、invokevirual、invokespecial、invokeinterface 。
为了说明他们的区别,还得说下JVM中类的存贮和方法的早/迟绑定。
1. Class的类方法的存放地方和属性:
JVM有一个所有线程间共享的“方法区”,用来存贮每个类结构的常数池、域、方法数据、方法和构造函数。包括类和实例初始化与接口类型初始化中用到的特殊方法。所以每当有线程调用某个类的方法时,都要从方法区调用。java类的方法有很多修饰,比如static、final、private等,这个决定了jvm在底层调用方法上的不同。
2.方法的早/迟绑定
简单来说,分辨一个方法是早绑定还是迟绑定可以通过是根据引用调用方法还是通过对象来调用方法。
当一个方法是static时,在任何地方都可以直接调用,比如Math.abs(4),这个时候就是早绑定,因为这里不需要new,当然没对象了。早绑定不仅仅限于static,当调用private方法时,也是早绑定,因为private只能被自身类方法调用。比如:
Java代码
class A{
private void methodA(){}
}
class B extends A{
private void methodB(){}
}
classA a = new classB();
这里是无法这么用a.methodA()和a.methodB(); (原因显而易见,这里就不说了)
我觉得这样理解private是静态绑定应该好点。
有了以上的说明,可以说清楚方法的具体区别了。
invokestatic:用于static修饰的方法。任何时候调用只需要所属的CLASS名,无需new,JVM可以直接映射到方法区,是执行速度最快的。如果static方法有参数,则invokestatic指令前还会有个指令,作用是把参数从栈弹出给invokestatic指令。(详细说明这里需要再详细解释下方法运行机制,这里以后再说,这里特别声明是为了和invokevirtual等方法做个区别)
invokevirtual:用于public和protected修饰的且没有static修饰的方法,在invokevirtual之前,总可以见到astore和aload的指令, 是因为在调用invokevirtual时,会从栈里弹出两个参数,是objectref和我们自定义的参数列表。objectref就是this,因为非static方法不是直接从方法区用的,所以得匹配所属类,是默认的隐式参数,无法从代码层指定objectref。参数列表就是我们自定义的传入参数了。invokevirtual是类的方法调用最慢的指令(因为迟绑定需要多重校验),但是却是运用最多的,java面向对象的多态性离不开它。
invokespecial:用于3种情况,前2种类默认的方法<init>()和super修饰的方法,它们可以为隐式,<init>()是默认的无参构造函数,super()是默认的调用父类构造函数的函数。当然我们也可以在代码层自定义些参数。invokespecial可以默认从构造函数里递归调用super(),而invokevirtual不行(动态绑定是只运行当前类中的方法)之前说过invokespecial是静态绑定的,如果换用动态绑定是会出错的(例如构造函数的例子),第三种是非static修饰的private方法,原因之前也说了。invokespecial的运行速度比较特殊,在super和init()时,我们可以不用关心(关心也无用,改不了),对于非static的private方法,速度是快于invokevirtual的。
invokeinterface:用于接口调用的情况,速度是最慢的,因为接口不知道类的具体信息,所以每次运行前得遍历整个类(校验+匹配),而invokevirtual是直接关联类的,方法偏移量是固定的。
这里再补充说明个问题,我看别的帖子说,有final声明的方法也是先绑定的,这里我不清楚,这里只说说我的想法
首先final是用于不可修改,不可继承的用途,而不是改变使用或者说调用的方法。
其次,《深入java虚拟机》中也只说了invokestatic和invokespecial是先绑定、invokeinterface和invokevirual没有说明,而我实践javap的时候,所有方法没有因为加了final而改变字节码的方法(不像static),有兴趣可以试试。
最后总结说下大致的代码优化规则。
首先,4种运行速度为:invokestatic > invokespecial > invokevirual > invokeinterface。
所以常用的方法是,
1. 根据具体的业务要求,分离出常用的任务写成static方法,加快速度。有人也怀疑static方法会不会占用更多的内存,我认为不会,因为无论是什么样的方法都得占用方法区的空间,调用也是引用调用。再说对于现在上G的内存,我们写的几K的东西也算不上多大开销。
2. 遵循高内聚,低耦合的模式,一个类只对外提供必要的public个protected方法,大部分的内部逻辑就用private修饰,一来速度快,二来也免得别人调用起来方法太多看的麻烦。
3. 对于接口来说,不是接口用的越多越好,抽象出来的接口应该越精简越好,我的亲身体会是接口多了很麻烦,毕竟越灵活的东西越难理解。
我对于方法调用的理解就到这么多,欢迎拍砖。
分享到:
相关推荐
### JVM学习笔记(一) #### 一、JVM概述与工具使用 JVM(Java Virtual Machine)是Java语言的核心组成部分之一,它为Java程序提供了一个跨平台的运行环境。本篇学习笔记主要介绍如何利用一系列工具来查看和监控JVM...
本篇JVM学习笔记主要涵盖了以下几个核心知识点: 1. **运行时数据区**: - **程序计数器**:记录当前线程执行的字节码的行号,用于线程恢复执行时跳转到正确位置。 - **Java虚拟机栈**:每个方法执行时创建的栈帧...
本文将深入探讨JVM中的访问控制器,主要基于“java之jvm学习笔记十一(访问控制器)-源码”这一主题,以及相关的源码分析。 首先,我们得了解Java的安全模型。Java安全模型基于一种称为安全管理器(SecurityManager)...
JVM的学习可以从其基本结构、代码编译和执行过程,以及内存管理和垃圾回收机制三个方面进行深入探讨。 首先,JVM的基本结构分为逻辑结构和物理结构。逻辑结构主要包括Java源码编译器、JVM执行引擎、类加载器等组件...
本篇JVM学习笔记主要关注对象声明、相关内存分配方法以及虚拟内存的物理和虚拟寻址概念。 首先,我们来看对象声明。在Java中,对象是在堆上创建的。例如,`CHeapObj` 类展示了如何在C++中模拟Java对象在堆上的分配...
这个资料包不仅涵盖了理论知识,还包含个人的学习笔记,对于学习和掌握JVM的各个方面都将大有裨益。无论是初学者还是经验丰富的开发者,都可以从中找到提升自己技能的宝贵资源。通过深入学习和实践,可以更好地理解...
堆内存主要用于存储对象实例,而栈内存则存储方法调用时的局部变量。除此之外,JVM还有方法区、程序计数器和本地方法栈等组成部分。 垃圾回收(GC,Garbage Collection)是JVM自动进行内存管理的重要机制,它的目标...
### JVM中篇笔记知识点 #### 一、Class 文件结构 ##### 1. 概述 - **字节码文件的跨平台性** - Java 的跨平台性体现在 "Write Once, Run Anywhere" (WORA),即一次编写,到处运行。Java 语言编写的源代码在编译...
### JVM学习笔记核心知识点整理 #### 一、引言与背景 随着软件开发技术的不断发展,Java作为一种广泛应用的编程语言,其背后的核心技术——Java虚拟机(JVM)的重要性日益凸显。掌握JVM不仅可以帮助开发者更好地理解...
Java虚拟机(JVM)是Java程序运行的基础,它是一个抽象的计算机系统,负责执行Java字节码。本文将深入探讨JVM的工作...这本《JVM工作原理学习笔记》应包含了这些内容的详细讲解,对于学习和提升JVM相关知识极具价值。
本文将深入探讨JVM中的访问控制器,并通过分析"java之jvm学习笔记十一(访问控制器) -源码"中的`MySecurityManager`来进一步理解其工作原理。 访问控制器的主要任务是对类、方法和字段的访问进行限制,防止恶意代码...
《JVM学习笔记》 Java虚拟机(JVM)是Java平台的核心组成部分,它负责运行所有的Java应用程序。这篇笔记将深入探讨JVM的工作原理、内存管理、类加载机制以及优化策略,帮助读者全面理解JVM并提升Java程序的性能。 ...
1. **方法调用**:当遇到invoke系列指令时,JVM会检查调用的目标方法是否与当前操作数栈上的类类型兼容。例如,如果试图调用私有方法,那么必须确保调用者是该方法所在的类或其子类。 2. **字段访问**:getfield和...
这份“JVM的学习笔记PDF版”应该包含了关于JVM的详细信息,帮助学习者深入理解这个复杂的系统。JVM允许Java代码跨平台运行,通过解释器、类加载器、垃圾收集器等组件实现“一次编写,到处运行”的理念。 1. **JVM...
本篇学习笔记将深入探讨这一主题,主要关注Java字节码的执行过程以及如何通过栈校验来防止非法操作。 Java字节码是由Java编译器生成的中间代码,它在JVM上运行前会经过类加载器的验证,其中栈校验是验证的一部分。...
### JVM学习笔记知识点详解 #### 一、JVM的基本结构 **JVM(Java Virtual Machine,Java虚拟机)**是一种可以执行Java字节码的虚拟机。它为Java提供了平台无关性,使得Java代码可以在任何安装了JVM的平台上运行。 ...
- 本地方法栈:与JVM栈类似,但服务于Java Native Interface(JNI)调用的本地方法。 - 堆内存:存放对象实例,进行垃圾回收的主要区域。 - 方法区(非堆):存储已加载的类信息、常量、静态变量等。 - 运行时...
本篇学习笔记将深入探讨这一机制,主要聚焦于步骤2的源码分析。在Java的世界里,类型安全至关重要,尤其是在多线程环境下,防止非法的类型访问和操作能避免潜在的安全风险和程序崩溃。 栈校验机制主要是为了执行...
- **操作数栈**: 用于临时存储计算过程中产生的中间结果,并参与方法调用时的参数传递。 当栈内存不足时,会抛出`StackOverflowError`。若无法扩展栈大小,则会抛出`OutOfMemoryError`。 #### 四、本地方法栈...
《JVM笔记(阳哥)》是一份深入探讨Java虚拟机(JVM)的资料,由阳哥精心整理。这份笔记涵盖了JVM的基础概念、内存管理、类加载机制、性能优化等多个方面,对于理解Java程序的运行机制以及提升开发效率具有重要的...