-
Java方法的调用机制:进出栈
2018-03-19 19:45:09每次调用方法,其实就是入栈操作,也就是栈中为该方法分配了一块空间,用于保存该方法中涉及到的变量每次方法调用结束,伴随着“方法出栈”操作,也就是栈中分配的空间被释放了熟悉Java方法的调用机制,可以充分理解...每次调用方法,其实就是入栈操作,也就是栈中为该方法分配了一块空间,用于保存该方法中涉及到的变量
每次方法调用结束,伴随着“方法出栈”操作,也就是栈中分配的空间被释放了
熟悉Java方法的调用机制,可以充分理解递归思想的运用
-
java方法的调用顺序
2019-09-03 23:17:01java有哪些方法引言
这篇文章酝酿了很久,有时想要写出来,又觉得还有更重要的需要学习,今天刚好在看JDK源码,想起这篇草稿,看来是时候写篇博客了。
Java方法分类
- 普通方法
一个类的普通方法,可能被子类继承。 - 构造方法
一个类默认会有一个不带参数的构造方法。 - 代码块
static修饰的代码块。 - 静态方法
声明为static的静态方法。
研究方向
首先我们来看一下没有父类继承情况下的方法执行顺序。
package JAVA原理及应用.方法执行顺序; import java.util.ArrayList; import java.util.List; /** * Created by haozhixin on 2019/9/10. */ public class MethodExcudeTest { private String name; public List list1 = new ArrayList(){ { System.out.println("普通变量方法执行了"); } }; public static List list = new ArrayList(){ { System.out.println("静态变量方法执行了"); } }; public MethodExcudeTest(){ System.out.println("默认的构造方法方法执行了"); } public MethodExcudeTest(String name){ this.name=name; System.out.println("重写的构造方法方法执行了"); } public static void method(){ System.out.println("静态方法执行了"); } static{ System.out.println("静态块执行了"); } { System.out.println("动态块执行了"); } public static void main(String[] args){ System.out.println("main方法执行了"); new MethodExcudeTest(); System.out.println("---------------------------------------"); new MethodExcudeTest("zhangdan"); } }
执行结果是
静态变量方法执行了 静态块执行了 main方法执行了 普通变量方法执行了 动态块执行了 默认的构造方法方法执行了 --------------------------------------- 普通变量方法执行了 动态块执行了 重写的构造方法方法执行了
由以上,我们看出五点: (1)静态代码块及变量在类加载时已经完成,所以main方法启动的打印日志在加载之后。 (2)静态代码块及变量在类的启动中只加载一次。 (3)静态块或者静态变量比非静态块优先执行 (4)满足第一个条件后,变量声明比方法声明优先执行 (5)对于static修饰的方法,调用才会执行
然后我们再来看有父类继承的情况,满不满足这个结论:
package JAVA原理及应用.方法执行顺序; import java.util.ArrayList; import java.util.List; /** * Created by haozhixin on 2019/9/10. */ public class MethodExcudeTestChild extends MethodExcudeTest { private String name; public List list1 = new ArrayList(){ { System.out.println("子类普通变量方法执行了"); } }; public static List list = new ArrayList(){ { System.out.println("子类静态变量方法执行了"); } }; public MethodExcudeTestChild(){ System.out.println("子类默认的构造方法方法执行了"); } public MethodExcudeTestChild(String name){ this.name=name; System.out.println("子类重写的构造方法方法执行了"); } public static void method(){ System.out.println("子类静态方法执行了"); } static{ System.out.println("子类静态块执行了"); } { System.out.println("子类动态块执行了"); } public static void main(String[] args){ System.out.println("main方法执行了"); new MethodExcudeTestChild(); System.out.println("---------------------------------------"); new MethodExcudeTestChild("zhangdan"); } }
执行结果:
静态变量方法执行了 静态块执行了 子类静态变量方法执行了 子类静态块执行了 main方法执行了 普通变量方法执行了 动态块执行了 默认的构造方法方法执行了 子类普通变量方法执行了 子类动态块执行了 子类默认的构造方法方法执行了 --------------------------------------- 普通变量方法执行了 动态块执行了 默认的构造方法方法执行了 子类普通变量方法执行了 子类动态块执行了 子类重写的构造方法方法执行了
可以看到结果是一样的。
总结
由以上,我们看出五点: (1)静态代码块及变量在类加载时已经完成,所以main方法启动的打印日志在加载之后。 (2)静态代码块及变量在类的启动中只加载一次。 (3)静态块或者静态变量比非静态块优先执行 (4)满足第一个条件后,变量声明比方法声明优先执行 (5)对于static修饰的方法,调用才会执行
作者:select you from me
来源:CSDN
转载请联系作者获得授权并注明出处。 - 普通方法
-
java方法的调用过程
2018-07-14 20:53:022.java方法的执行 3.机器指令的格式 4.机器指令的执行模式—基于操作数栈的模式 三种语言存在的关系 1.前提 JVM在编译Bootstrap.java 的过程中,在将源代码编译成二进制机器码的同时,会判断其中的每一个方法...我们知道,class 文件时 JVM能够识别的二进制文件,其中通过特定的结构描述了每个方法的定义。
1.前提
JVM在编译Bootstrap.java 的过程中,在将源代码编译成二进制机器码的同时,会判断其中的每一个方法的三个信息:
1 ). 在运行时会使用到的局部变量的数量(作用是:当JVM为方法创建栈帧的时候,在栈帧中为该方法创建一个局部变量表,来存储方法指令在运算时的局部变量值)
2 ). 其机器指令执行时所需要的最大的操作数栈的大小(当JVM为方法创建栈帧的时候,在栈帧中为方法创建一个操作数栈,保证方法内指令可以完成工作)
3 ). 方法的参数的数量2.java方法的执行
一般地,对于java方法的执行,在JVM在其某一特定线程的虚拟机栈(JVM Stack) 中会为方法分配一个 局部变量表,一个操作数栈,用以存储方法的运行过程中的中间值存储。
由于JVM的指令是基于栈的,即大部分的指令的执行,都伴随着操作数的出栈和入栈3.机器指令的格式
所谓的机器指令,就是只有机器才能够认识的二进制代码(这里指的是jVM)一个机器指令分为两部分组成:
注:
a). 如上图所示JVM虚拟机的操作码是由一个字节组成的,也就是说对于JVM虚拟机而言,其指令的数量最多为 2^8,即 256个;
b). 上图中的操作码如:b2,bb,59….等等都是表示某一特定的机器指令,为了方便我们识别,其分别有相应的助记符:getstatic,new,dup…. 这样方便我们理解。
4.机器指令的执行模式—基于操作数栈的模式
对于传统的物理机而言,大部分的机器指令的设计都是寄存器的,物理机内设置若干个寄存器,用以存储机器指令运行过程中的值,寄存器的数量和支持的指令的个数决定了这个机器的处理能力。
但是Java虚拟机的设计的机制并不是这样的,Java虚拟机使用操作数栈 来存储机器指令的运算过程中的值。所有的操作数的操作,都要遵循出栈和入栈的规则,所以在《Java虚拟机规范》中,你会发现有很多机器指令都是关于出栈入栈的操作。
三种语言存在的关系
机器指令:二进制代码
汇编语言对应着不同的机器语言指令集,通过汇编过程转换成机器指令。
引用网址:https://blog.csdn.net/luanlouis/article/details/50412126 -
java方法调用原理——虚拟机中方法调用
2017-09-16 15:02:03为了更加深入的理解方法的覆盖和覆写原理需要了解java方法的调用原理首先解释一下方法调用: 方法调用不等同于方法执行,方法调用阶段的唯一任务就是确定被调用方法的版本(即确定具体调用那一个方法),不涉及方法...为了更加深入的理解方法的覆盖和覆写原理需要了解java方法的调用原理
首先解释一下方法调用:
方法调用不等同于方法执行,方法调用阶段的唯一任务就是确定被调用方法的版本(即确定具体调用那一个方法),不涉及方法内部具体运行。java虚拟机中提供了5条方法调用的字节码指令:
invokestatic:调用静态方法 invokespecial:调用实例构造器<init>方法、私有方法、父类方法 invokevirtual:调用所有虚方法。 invokeinterface:调用接口方法,在运行时再确定一个实现该接口的对象 invokedynamic:运行时动态解析出调用的方法,然后去执行该方法。
方法调编译成Class字节码后的状态:
Class文件的编译过程中不包含传统编译中的连接步骤,一切方法调用在Class文件里存储的都只是符号引用,而不是具体的方法执行入口地址(即直接引用)。所以对于java的方法调用过程就变的复杂起来,需要在类加载期间,甚至是运行期间才能确定目标方法的直接调用。
关于具体的类加载机制可以参考JVM类加载机制
1、解析阶段
Class文件里所有的方法调用都是一个常量池中的符号引用,在类的解析阶段,会将其中一部分符号引用转化为直接引用。转化的这部分方法调用必须是:在程序运行之前就有一个可以确定的调用版本,并且这个调用版本在程序运行期间是不可改变的。
即:编译期可知,运行期不变的方法调用
这种类型的方法主要有:静态方法、私有方法。
只要能被invokestatic和invokespecial指令调用的方法都可以在解析阶段中确定唯一调用版本。符合这个条件主要有:静态方法、私有方法、实例构造器方法、父类方法。他们在类加载的时候就会把符号引用解析为该方法的直接引用。
2、分派
就是如何确定执行哪个方法,这里详细解释了重载和重写。
静态分派
首先看一个重载的例子
public class Main2 { class A{ } class B extends A{ } public static void f(A a) { System.out.println("A"); } public static void f(B b) { System.out.println("B"); } public static void main(String[] args) { A a = new Main2().new B(); f(a); } }
输出:A
这里将A称为静态类型或者外观类型,B称为实际类型。
编译器在运行前只知道一个对象的静态类型,并不知道对象的实际类型。
f方法经过了重载,有两个不同的参数,虚拟机方法调用时,他会直接使用静态类型进行匹配。也就是说:重载时是通过参数的静态类型而不是实际类型作为判定依据。并且静态类型是在编译期可知的,因此在编译阶段,javac编译器就可以根据参数类型确定具体使用哪个重载版本。
- 所有依赖静态类型来定位方法执行版本的分派动作称为静态分派。
- 静态分派的典型应用就是方法重载。
- 静态分派发生在编译阶段,因此确定静态分派的动作实际上不是由虚拟机来执行的。
动态分派
这个分派体现了重写
主要和invokevirtual方法调用字节码有关,运行过程如下:
- 找到操作数栈顶的第一个元素所指向的对象的实际类型,记为C;
- 在C中寻找与常量中的描述符合简单名都一致的方法,进行权限校验,如通过则返回这个方法的直接引用,查找结束;如果不通过,返回异常。
- 否则,按照继承关系从下往上依次对C的各个父类进行第2步搜索和验证。
- 如果始终没有找到合适的方法,则抛出异常。
虚拟机动态分派的实现
最常用的手段就是在方法区中建立一个虚方法表,如果一个方法在子类中没有被重写,那么子类的虚方法表里的地址入口就和父类对应方法地址入口一致。
即:每个对象都建立一个如上图的方法虚方法表,表中列出每个对象的所有方法,包括继承的方法,如果重写了对应的方法,则对应的地址就是重写方法的地址,如果没有重写就是原来的方法地址。
-
JAVA类之间方法的调用
2018-11-02 23:39:15JAVA类方法的调用一、静态方法调用其他方法:1. 静态方法调用非静态方法2.静态方法调用静态方法二、非静态方法调用其他方法1.非静态方法在同一类内调用其他方法2.非静态方法在不同类之间调用其他方法 注:调用方法... -
Scala和Java方法的相互调用
2019-08-07 14:08:27在Scala中调用java的方法,很简单,直接导入传递参数就可以进行调用了. 但是在Java中调用Scala的方法呢? 经过测试,也是很简单,静态方法直接传递参数,就可以调用了,非静态的方法,使用对象也可以调用方法 具体如下:... -
Java的方法调用机制
2014-06-14 00:09:50在Java中,方法调用是非常基本、非常拼 -
java 判断方法调用是否超时 设置方法调用的超时时间
2017-09-08 10:44:55java 判断方法调用是否超时 设置方法调用的超时时间public class Test { public static void main(String[] args) { Executor executor=Executors.newSingleThreadExecutor(); FutureTask<String> future=new ... -
java的静态方法调用
2019-01-13 21:29:34首先你要知道java中静态方法调用有哪几种? 例如一个静态方法如下: (1) 通过类名直接调用 调用格式: 类名.方法名 Test.aa() 前提是这个静态方法是要有返回值!这个静态方法是公共的(public),本类调用的话... -
详解java虚拟机方法调用
2018-06-01 14:48:57在类加载的解析阶段,会将其中的一部分符号引用转化为直接引用,这种解析能成立的前提是:方法在程序真正运行之前就有一个可确定的调用版本,并且这个方法的调用版本在运行期是不可改变的。 换... -
C++调用Java方法
2018-10-17 16:02:23最近在搞JNI那块,发现网上很多都是Java调用JNI,然后...另一种是Java调用了C++,然后在该调用的C++里又回调另外的一个Java方法。其实这两种方法(或其他方法),都是要用到 JNIEnv,有关JNI的讲解可查阅此文章http... -
Java调用Python程序方法总结
2018-01-17 23:58:07实际工程项目中可能会用到Java和python两种语言结合进行,这样就会涉及到一个问题,就是怎么用Java程序来调用已经写好的python脚本呢,一共有三种方法可以实现,具体方法分别为大家介绍: 1. 在java类中直接执行... -
Java远程方法调用
2013-01-26 10:09:29主要参考 ... http://bbs.chinaunix.net/thread-1179312-1-1.html ...Java 远程处理 ... Java远程方法调用(RMI)提供了Java程序语言的远程通讯功能,这种特性使客户机上运行的程序可以调用远程服务器上的对象,使Java -
Java方法调用的优先级问题
2017-03-29 13:05:45实现Java多态性的时候,关于方法调用的优先级: 我们这样假设下,super(超类)、this(当前类对象)、show(方法)、object(对象),方法调用优先顺序: ①this.show(object)>②super.show(object)> ③this.... -
JAVA方法调用在内存中的实现
2018-01-30 21:52:49上面是一个java程序...栈有一个特点:先进后出,java中方法的调用即是进栈(push) 方法的结束就是出栈(pop) 接下来用一张内存图演示方法在内存JVM的调用 入栈顺序main->m1->m2->m3 出栈顺序 m3->m2->m1->main -
java 反射调用方法,方法内部调用了外部的jar
2016-09-19 04:33:21java 反射调用方法,方法内部调用了外部的jar,该外部jar怎么动态加载进来,现在报错: java.lang.reflect.InvocationTargetException at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun... -
Java 静态方法与非静态方法的调用
2019-05-28 17:35:41调用静态方法 一般格式如下 类名.方法() //应为静态方法属于类本身,在同一个类中可以直接 调用 方法() 调用非静态方法 格式 对象名.方法() 一个小demo 方便理解 package me; public class Book { public void... -
JAVA中方法的调用(详细整理)
2018-05-23 15:00:55JAVA中方法的调用主要有以下几种:1.非静态方法非静态方法就是没有 static 修饰的方法,对于非静态方法的调用,是通过对 象来调用的,表现形式如下。对象名.方法()eg:public class InvokeMethod{ public static ... -
Java中的方法重写调用
2018-10-16 21:11:20上学期学了java,一个暑假没有用,很多java的“精髓”都忘记了。周末在写数据结构的作业的时候,要求写一个循环链表的类,并且继承之前写的一个线性表的类。因为重写的一些重要的东西忘记了,花了大量的时间一直在报... -
Java方法的嵌套与递归调用
2020-03-20 15:15:32方法嵌套的概念其实比较好理解,就是在调用方法的过程中又遇到了方法的调用,在刚开始接触的时候虽然在逻辑上能够理解为什么运行结果是这样的,但是对于代码执行的过程还是感觉有些绕。递归是一种计算过程或方法,是... -
java 方法调用,方法参数调用方式是值传递
2018-01-04 16:21:34很多程序设计语言(特别是C++和Pasal)提供了两种参数传递的方式:值传递和引用调用。 在java程序设计语言中,对基本数据类型的参数是值传递,对象引用类型的参数是对象引用的值传递。总结一下就是值传递; 方法... -
Java静态方法调用非静态方法
2018-09-19 20:23:42静态方法(static mehod)不能直接调用非静态方法(non-static method),可以通过一个对象的引用传入静态方法中,再去调用该对象的非静态方法。在主函数(static方法)中,经常创建某个类的实例,再利用其引用变量调用他... -
深入理解java方法调用时的参数传递
2017-11-09 18:08:20深入理解java方法调用与参数传递,解决以下问题:Java方法调用是如何传递参数的?被调用方法对调用方法内的变量有什么影响?java能使用返回值void的中间方法对变量进行加工吗?为什么静态成员变量的改变影响是全局的... -
java 获取当前方法的调用栈
2019-05-17 11:38:51本文的出发点在于处理现场问题时,想看到方法的调用过程 StackTrace(堆栈轨迹)存放的就是方法调用栈的信息,每次调用一个方法会产生一个方法栈,当前方法调用另外一个方法时会使用栈将当前方法的现场信息保存在此... -
Java中调用方法的几种方式
2018-11-12 18:50:46一般的,在Java语言中,调用方法有三种方式。 第一种:通过对象名.方法名进行调用,这是最普通的也是最常见的一种调用方式。 第二种:通过new关键字调用构造方法,这种是在实例化对象时使用的方式。 第三种:通过... -
Dalvik虚拟机中Java native方法的调用过程
2018-02-06 19:55:26我们知道,Java native方法的注册形式有两种,一种是主动注册,一种是默认的被动注册,如果我们希望弄清楚java native方法的调用过程,我们首先就需要搞清楚两种注册方式的实现原理,下面我们先分别看看这两种注册... -
java 在方法内调用方法
2018-10-12 21:34:05类似于c语言里的函数,就想main函数里面调用其他函数一样,可以在方法里调用其他方法 class Person//类的建立 { private String name; private int age; private void talk()//定义私有方法talk,该方法只能在... -
java中调用start()方法和调用run()方法的区别
2018-12-06 17:08:43java中调用start()方法和调用run()方法的区别 调用start()会开启线程,让开启的线程去执行run()方法中的线程任务。 调用run(),线程并未开启,去执行run()的只有主线程 ... -
java子类父类方法的调用
2018-06-10 20:16:44如果子类重写了父类的方法,会调用子类的方法,若未重写则调用父类的方法。package com.test; /** * @author Administrator * @date 2018/6/9 */ public class TestParent { public void testA()...