zoukankan      html  css  js  c++  java
  • 一段Java代码是如何执行的?

    1. 编译成class

    众所周知,Java代码是不能直接在jvm上执行的,执行的是class文件,将Java代码编程class文件,需要编译
    常用的编译方法是:javac xxx.java
    但目前常见的java编辑工具,如eclipse和ideal都自带自动编译动能

    2. jvm的构成

    让我们回忆一下jvm的构成:

    主题上分为五个部分:
    方法区,本地方法栈,java堆,java栈,程序计数器
    其中,java栈,本地方法栈,程序计数器为线程私有,其余为线程共享
    那么,方法在哪个地方执行呢?
    java栈。
    栈的遵循的方式是先进后出,java栈中方法的执行也遵循此规律,方法执行的步骤又称为栈帧。

    3. 方法的顺序执行和栈帧

    上代码:
    -Java 代码

     1 public class Main {
     2     public static void a(){
     3         b();
     4     }
     5 
     6     public static void b(){
     7         c();
     8     }
     9 
    10     public static void c(){
    11         System.out.println("Hello world!");
    12     }
    13 
    14     public static void main(String[] args) {
    15         a();
    16     }
    17 }
    View Code

     上面是一段很简单的代码,主体上就是:
    (1)一个Main类
    (2)上面定义了一个main方法
    (3)该main方法调用了静态方法a
    (4)方法a调用方法b
    (5)方法b调用方法c
    (6)方法c打印了“Hello world!”
    前文说过,java定义的非本地方法都是在java栈内执行的,一方法一栈帧
    所以假设
    mian方法对应栈帧m
    a方法对应栈帧a
    b方法对应栈帧b
    c方法对应栈帧c
    根据方法的调用,入栈顺序为:m,a,b,c
    所以,栈帧出栈(即方法执行)顺序为:c,b,a,m

    4. class文件反编译过后的样子

    上一节,方法或栈帧在java栈的执行顺序
    但在方法体内的内容是怎么执行的呢。
    前文提到,jvm执行的是class文件,而class文件内是什么?
    class文件内是一组指令集。
    如何证明呢,还是再看一段代码。
    -Java 代码

     1 public class Calculator{
     2     public int add(){
     3         int n = 10;
     4         int m = 20;
     5         int r = n + m;
     6         return r;
     7     }
     8 
     9     public static void main(String[] args) {
    10         Calculator calculator = new Calculator();
    11         int a = calculator.add();
    12         System.out.println(a);
    13     }
    14 }
    View Code

     如上代码,实现的功能是:
    (1)定义两个变量,相加
    (2)main方法new对象,调用方法
    但,class文件是不可以直接查看的。
    我们可以采用反编译的方法,反编译命令:、
    javap -c xxx.class

     上述文件反编译后的样子如下:

     每个方法下面的Code,都是一组指令集。

    5. 指令集详解

    在讨论指令集之前,首先要讲一个概念,那就是对栈帧进一步拆分。
    栈帧一共分为四个部分:局部变量表、操作数栈、动态链接、方法返回地址
    其中,局部变量表和操作数栈是最重要的两个部分
    局部变量表存放在方法中定义的局部变量
    操作数栈相当于jvm的一个缓存
    所有的操作都必须在此处进行
    所有的变量都必须加载到操作数栈才能被使用
    所以,所谓指令,就是在局部变量表和操作数栈来回倒腾的过程。
    下面对指令进行分类讲解:
    (1)入栈指令
    整型入栈指令:
    取值-1~5采用iconst指令;
    取值-128~127采用bipush指令;
    取值-32768~32767采用sipush指令;
    取值-2147483648~2147483647采用ldc指令。
    非整型入栈指令:
    float,String类型也使用ldc指令
    double和long类型使用ldc_2w
    boolean类型视作0和1
    null的入栈指令为:aconst_null
    (2)存储指令
    将操作数栈中的常量保存在局部变量表中的某个位置
    如:
    istore_1:将上面入栈的整型常量保存在局部变量表中的第1个位置
    fstore_2:将上面入栈的浮点常量保存在局部变量表中的第2个位置
    dstore_10:将上面入栈的双浮点常量保存在局部变量表中的第10个位置
    lstore_20:将上面入栈的长整常量保存在局部变量表中的第20个位置
    astore_100:将上面入栈的引用常量保存在局部变量表中的第100个位置
    (3)变量入栈指令
    iload_1:局部变量表中的第1个位置的整型变量入栈
    fload_2:局部变量表中的第1个位置的浮点型变量入栈
    dload_10:局部变量表中的第1个位置的双浮点型变量入栈
    lload_20:局部变量表中的第1个位置的长整型变量入栈
    aload_100:局部变量表中的第100个位置的引用型变量入栈
    (4)计算指令
    加:iadd、ladd、fadd、dadd
    减:isub、lsub、fsub、dsub
    乘:imul、lmul、fmul、dmul
    除:idiv、ldiv、fdiv、ddiv
    注意:栈顶计算,一次只能计算一个表达式

     来源:华为云社区
    链接:https://bbs.huaweicloud.com/blogs/250559

  • 相关阅读:
    vue-router重写push方法,解决相同路径跳转报错
    Vue中的权限管理怎么做
    linux启动过程中建立临时页表
    用redis当作LRU缓存
    用IPV6隧道连接IPV4孤岛
    redis协议规范
    nginx的脚本引擎(二)rewrite
    nginx的脚本引擎(一)
    nginx的变量系统
    Singleton
  • 原文地址:https://www.cnblogs.com/hoganhome/p/14822399.html
Copyright © 2011-2022 走看看