最近有空,继续写写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. 对于接口来说,不是接口用的越多越好,抽象出来的接口应该越精简越好,我的亲身体会是接口多了很麻烦,毕竟越灵活的东西越难理解。
我对于方法调用的理解就到这么多,欢迎拍砖。
分享到:
相关推荐
Runtime或System类调用exit()方法或Runtime调用half()方法 JVM的框架: 执行引擎: (字节)解释器 + JIT(java即时编译器) 前者是用 PC计数器 来依次编译每一行代码解释为本地机器指令; 后者是通过 寻找热点代码 进行...
《Java JDK 7学习笔记》将IDE操作纳为教学内容之一,使读者能与实践结合,提供的视频教学能更清楚地帮助读者掌握操作步骤。 内容简介 书籍 计算机书籍 《java jdk 7学习笔记》是作者多年来教学实践经验的总结...
要请求垃圾收集,可以调用下面的方法之一: System.gc() Runtime.getRuntime().gc() 37.String s = new String(\"xyz\");创建了几个String Object? 答:两个对象,一个是“xyx”,一个是指向“xyx”的引用对象s。...
在不同的操作系统之上可以不用做任何代码的修 改 直接使用 a) 字节码文件:字节码文件不包括任何内存布 局信息 与操作系统和硬件毫无关系 (Java 的内存分布是在运行的时候才动态分配的) b) JVM:真正解释字节码文件...
Scala 是一门多范式(multi-paradigm)的编程语言,设计初衷是要集成面向对象编程和函数式编程的各种特性。...Scala 源代码被编译成Java字节码,所以它可以运行于JVM之上,并可以调用现有的Java类库。
远程方法调用(RMI) 正确协同多个对象中的共享状态 正确协同远程对象本身状态的访问 Swing和AWT 事件处理器与访问共享状态的其他代码都要采取线程安全的方式实现 框架通过在框架线程中调用...
JVM的重要性不言而喻,这个是学习JVM是看视频和读《深入理解JVM》时做的一些笔记,用于复习参考。 读书笔记 第2章:java内存模型和内存溢出异常 1.运行时数据区域 1.程序计数器:线程私有 2.java虚拟机栈:线程私有...
springboot学习笔记 spring基础 Spring概述 Spring的简史 xml配置 注解配置 java配置 Spring概述 Spring的模块 核心容器CoreContainer Spring-Core Spring-Beans ...
interrupted是Thread类的静态方法,里面调用了isTnterrupted方法[currentThread().isInterrupted()],测试当前线程是否已经中断,线程的中断状态由该方法清除 isInterrupted是Thread类的实例方法,不清除中断标志 yield...
本仓库记录了我的Java学习进阶之路,涵盖了Java基础、JDK源码、JVM中的重要知识,附有代码和博客讲解,旨在提供一个Java在线共享学习平台,帮助更多的Java学习入门者进阶。 Java学习 本仓库记录了我的Java学习进阶...
积分java源码Java 11 Java SE ...表达式由变量、运算符和方法调用组成。 表达式计算为单个值。 表达式是计算值的东西,而语句是做某事的一行代码。 某些表达式可以通过以分号结尾的方式组成语句,例
工厂方法模式:用来生产同一等级结构中的固定产品(支持增加任意产品,不用修改源代码)将工厂类调整为工厂接口,需要什么类型的工厂就使用该类实现该工厂,创建相应的产品。 :用来生产不同产品族的全部产品(对于...
系统设计 1 jive设计思路 2 jive的工作内幕 3 Jive源代码研究 4 Jive中的设计模式 5 jive学习笔记 <br> 设计模式 1 大道至简-Java之23种模式一点就通 2 设计模式...
这是一份总结的学习笔记 路漫漫其修远兮,吾将上下而求索 可阅读可评论可分享可转载,希望向优秀的人学习 前言 Scala 是一门多范式(multi-paradigm)的编程语言,设计初衷是要集成面向对象编程和函数式编程的各种...
系统设计 1 jive设计思路 2 jive的工作内幕 3 Jive源代码研究 4 Jive中的设计模式 5 jive学习笔记 <br> <br> 数据库设计 1 Jive Forums数据库说明(英文) 2 Jive KB...
具体事务和监听请参考文章:redis学习笔记之事务 暂时找到三种实现方式: 1. 通过jedis.setnx(key,value)实现 import java.util.Random; import org.apache.commons.pool.impl.GenericObjectPool.Config; import ...
因为类调用时需要实例化,开销比较大,比较消耗资源,所以当性能是最重要的考量因素的时候,比如单片机、嵌入式开发、Linux/Unix等一般采用面向过程开发。但是,面向过程没有面向对象易维护、易复用、易扩展。 面向...
│ 淘淘商城第一天笔记.docx │ ├─02.第二天 │ 07.商品类目选择完成.avi │ 01.课程计划.avi │ 02.展示首页.avi │ 03.分页插件01.avi │ 04.分页插件的使用方法.avi │ 05.商品列表展示.avi │ 06.商品类目...
程序员面试刷题的书哪个好 ...通常来说,我们用new创建对象后,才能调用这个对象的方法。否则,并未获得任何对象。 通常,我们需要创建一个对象,来访问这个对象的数据或方法,因为非static域和方法必须和
向下,生动清晰阐述JVM原理,内存管理,垃圾回收算法,系统调用,多线程及各种锁实现源码分析,BIO/NIO/AIO到Netty源码原理,全程项目贯穿,推动理论实践,上课等于上班,经验超过传统教学后工作一年经验,夯实的...