用Java手写jvm之模拟数组相关操作

news2024/10/1 17:22:07

写在前面

本文看下如何模拟数组相关的操作,主要是实现数组相关的指令,关于数组相关的指令可以参考这篇文章。

1:正文

简单起见这里我们仅仅实现int基础数据类型的一维数组。

  • newarray指令对应的类
package com.dahuyou.tryy.too.simulate.interpreter.instructions.references;

import com.dahuyou.tryy.too.simulate.interpreter.instructions.base.BytecodeReader;
import com.dahuyou.tryy.too.simulate.interpreter.instructions.base.Instruction;
import com.dahuyou.tryy.too.simulate.interpreter.runtime.area.Frame;
import com.dahuyou.tryy.too.simulate.interpreter.runtime.area.OperandStack;
import com.dahuyou.tryy.too.simulate.interpreter.runtime.area.heap.ClassLoader;
import com.dahuyou.tryy.too.simulate.interpreter.runtime.area.heap.methodarea.Class;
import com.dahuyou.tryy.too.simulate.interpreter.runtime.area.heap.methodarea.Object;

public class NEW_ARRAY implements Instruction {

    private byte atype;

    @Override
    public void fetchOperands(BytecodeReader reader) {
        this.atype = reader.readByte();
    }

    @Override
    public void execute(Frame frame) {
        // 获取操作数栈
        OperandStack stack = frame.operandStack();
        // 弹出操作数栈栈顶的int类型整数,作为将要创建的数组的大小
        int count = stack.popInt();
        if (count < 0) {
            throw new NegativeArraySizeException();
        }

        // 获取类加载器
        ClassLoader classLoader = frame.method().clazz().loader();
        Class arrClass = getPrimitiveArrayClass(classLoader, this.atype);
        Object arr = arrClass.newArray(count);
        stack.pushRef(arr);

    }
    // ...
}
  • iastore指令对应的类
/**
 * 将栈顶的int类型数据存储到指定数组的指定位置
 * 即给int数组某位置元素赋值😂😂😂
 */
public class IASTORE extends InstructionNoOperands {

    @Override
    public void execute(Frame frame) {
        OperandStack stack = frame.operandStack();
        // 操作数栈中弹出一个元素作为要设置的目标值
        int val = stack.popInt();
        // 操作数栈中弹出一个元素作为要设置的元素的位置
        int idx = stack.popInt();
        System.out.println("IASTORE指令:从操作数栈栈中弹出要设置的元素和位置");
        Object arrRef = stack.popRef();

        checkNotNull(arrRef);
        // 这里是通过将真正的数组数据存储到Object中来模拟的,所以还是从Object中来获取,注意这里的Object是我们自定义的模拟的Object,不是jdk的java.lang.Object
        int[] ints = arrRef.ints();
        checkIndex(ints.length, idx);
        // 完成数组赋值,IASTORE指令工作done!
        ints[idx] = val;
        System.out.println("IASTORE指令:完成数组元素赋值");
    }

}
  • iaload对应的类
public class IALOAD extends InstructionNoOperands {

    @Override
    public void execute(Frame frame) {
        OperandStack stack = frame.operandStack();
        // 从操作数栈中弹出要获取元素的数组索引位置
        int idx = stack.popInt();
        Object arrRef = stack.popRef();

        checkNotNull(arrRef);
        int[] ints = arrRef.ints();
        checkIndex(ints.length, idx);
        // 从指定的索引位置获取数组元素,并将获取到的元素要到操作数栈的栈顶
        stack.pushInt(ints[idx]);
        System.out.println("IALOAD指令:从操作数栈中弹出要获取元素的数组索引位置");
        System.out.println("IALOAD指令:从指定的索引位置获取数组元素,并将获取到的元素要到操作数栈的栈顶");
    }

}
  • arraylength指令
public class ARRAY_LENGTH extends InstructionNoOperands {

    @Override
    public void execute(Frame frame) {

        OperandStack stack = frame.operandStack();
        Object arrRef = stack.popRef();
        if (null == arrRef){
            throw new NullPointerException();
        }

        int arrLen = arrRef.arrayLength();
        stack.pushInt(arrLen);
        System.out.println("ARRAY_LENGTH: 指令执行,获取数组长度并将结果压倒操作数栈的栈顶");
    }

}
  • 测试
    main测试类:
package com.dahuyou.tryy.too.simulate.interpreter;

import com.dahuyou.tryy.too.simulate.interpreter.parse.clazz.classpath.Classpath;
import com.dahuyou.tryy.too.simulate.interpreter.parse.clazz.clazzfile.ClassFile;
import com.dahuyou.tryy.too.simulate.interpreter.parse.clazz.clazzfile.MemberInfo;
import com.dahuyou.tryy.too.simulate.interpreter.parse.clazz.cmd.Cmd;
import com.dahuyou.tryy.too.simulate.interpreter.runtime.area.heap.ClassLoader;
import com.dahuyou.tryy.too.simulate.interpreter.runtime.area.heap.methodarea.Class;
import com.dahuyou.tryy.too.simulate.interpreter.runtime.area.heap.methodarea.Method;

/**
 * -Xthejrepath     D:\programs\javas\java1.8/jre -Xthetargetclazz     D:\test\itstack-demo-jvm-master\tryy-too-simulate-classload-load-clazz\target\test-classes\org\itstack\demo\test\HelloWorld
 */
public class Main {

    public static void main(String[] args) {
        Cmd cmd = Cmd.parse(args);
        if (!cmd.ok || cmd.helpFlag) {
            System.out.println("Usage: <main class> [-options] class [args...]");
            return;
        }
        if (cmd.versionFlag) {
            //注意案例测试都是基于1.8,另外jdk1.9以后使用模块化没有rt.jar
            System.out.println("java version \"1.8.0\"");
            return;
        }
        startJVM(cmd);
    }

    private static void startJVM(Cmd cmd) {
        // 创建classpath
        Classpath cp = new Classpath(cmd.thejrepath, cmd.classpath);
//        System.out.printf("classpath:%s class:%s args:%s\n", cp, cmd.getMainClass(), cmd.getAppArgs());
        System.out.printf("classpath:%s parsed class:%s \n", cp, cmd.thetargetclazz);
        //获取className
//        String className = cmd.getMainClass().replace(".", "/");
        try {
//            byte[] classData = cp.readClass(className);
            /*byte[] classData = cp.readClass(cmd.thetargetclazz.replace(".", "/"));
            System.out.println(Arrays.toString(classData));
            System.out.println("classData:");
            for (byte b : classData) {
                //16进制输出
                System.out.print(String.format("%02x", b & 0xff) + " ");
            }*/
            // 创建类加载器准备加载类
            /**
             * 加载3个阶段
             * 1:加载
             *      找到字节码,并将其存储到原元空间(<=7方法区),然后该类,该类父类,父接口也加载并在堆中生成对应的Class对象
             * 2:链接
             *      验证:验证文件内容的合法性,如是否cafebabe打头,结构是否符合定义
             *      准备:主要是给静态变量申请内存空间,以及赋初始值,如int,short这种则给默认值0
             *      解析:符号引用(指向类或者方法的一个字符串)转换为直接引用(jvm的内存地址)
             * 3:初始化
             *      执行<init>,<clinit>方法,完成静态变量的赋值
             */
            ClassLoader classLoader = new ClassLoader(cp);
            String clazzName = cmd.thetargetclazz.replace(".", "/");
            Class mainClass = classLoader.loadClass(clazzName);
            Method mainMethod = mainClass.getMainMethod();
            new Interpreter(mainMethod, true);


            /*// 创建className对应的ClassFile对象
            ClassFile classFile = loadClass(clazzName, cp);
            MemberInfo mainMethod = getMainMethod(classFile);
            if (null == mainMethod) {
                System.out.println("Main method not found in class " + cmd.classpath);
                return;
            }
            // 核心重点代码:通过解释器来执行main方法
            new Interpreter(mainMethod);*/
        } catch (Exception e) {
            System.out.println("Could not find or load main class " + cmd.getMainClass());
            e.printStackTrace();
        }
    }

    /**
     * 获取main函数,这里我们要模拟是执行器执行main函数的过程,当然其他方法也是一样的!!!
     * @param classFile
     * @return
     */
    private static MemberInfo getMainMethod(ClassFile classFile) {
        if (null == classFile) return null;
        MemberInfo[] methods = classFile.methods();
        for (MemberInfo m : methods) {
            if ("main".equals(m.name()) && "([Ljava/lang/String;)V".equals(m.descriptor())) {
                return m;
            }
        }
        return null;
    }

    /**
     * 生成class文件对象
     * @param clazzName
     * @param cp
     * @return
     */
    private static ClassFile loadClass(String clazzName, Classpath cp) {
        try {
            // 获取类class对应的byte数组
            byte[] classData = cp.readClass(clazzName);
            return new ClassFile(classData);
        } catch (Exception e) {
            System.out.println("无法加载到类: " + clazzName);
            return null;
        }
    }

}

定义需要解析的类:

public class HelloWorld {

    public static void main(String[] args) {
      /*  long x = fibonacci(10);
        System.out.println(x);*/
//        returnALong();
        // new int[8]; newarray指令
        int[] intArr = new int[8];
        // iastore指令
        intArr[0] = 89;
        // iaload指令
        int pos0 = intArr[0];
        // arraylength指令
        int arraylength = intArr.length;
    }

    public static long returnALong() {
        long longResult = 99;
        return longResult;
    }
    //斐波那契数列(Fibonacci sequence)
    /*private static long fibonacci(long n) {
        if (n <= 1) {
            return n;
        } else {
            return fibonacci(n - 1) + fibonacci(n - 2);
        }
    }*/

}

配置program argument:
在这里插入图片描述
运行:
在这里插入图片描述

写在后面

参考文章列表

Java数组的类名是什么以及数组相关操作的指令有什么? 。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1991117.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

猫咪不爱喝水又挑食,终于找到适合的补水罐

我已经被她搞疯掉了,养了快两年,特别不爱喝水。喂的是干粮&#xff0c;干粮本身就水少&#xff0c;加上她不爱喝水&#xff0c;我都怀疑它一天有没喝够20ml没有&#xff0c;太可怕了&#xff0c;只能拿针管喂。我看过很多科普,换过每天勤换水,水碗离猫粮很远,水碗不会太小不存在…

2025年第六届教育和信息技术进展国际会议(AEIT 2025)将在日本福冈召开!

2025 第六届教育和信息技术进展国际会议将于 2025 年 1 月 10-12 日在日本福冈举行&#xff0c;AEIT2025旨在为全世界的科学家、研究人员、工程师和工业从业人员提供一个良好的论坛&#xff0c;展示和讨论教育技术领域的最新技术进展以及未来的发展方向和趋势。 会议官网&#…

【HarmonyOS NEXT星河版开发学习】小型测试案例08-人气卡片

个人主页→VON 收录专栏→鸿蒙开发小型案例总结​​​​​ 基础语法部分会发布于github 和 gitee上面&#xff08;暂未发布&#xff09; 前言 鸿蒙开发中的绝对定位和层级是关键的布局和设计概念&#xff0c;它们通过特定的属性和方式决定了组件在界面上的位置和层叠顺序。 知识…

Fast Planner规划算法(三)—— Fast Planner后端之轨迹优化与轨迹优化与时间重分配

本系列文章用于学习记录Fast-Planner规划算法的相关内容&#xff0c;主要学习资料是深蓝学院的移动机器人运动规划课程 三、Fast Planner后端之轨迹优化 在上一篇文章中&#xff0c;我们给出了 Fast Planner中的B样条曲线的表达式&#xff0c;在给定时间区间后&#xff0c;唯一…

【从零开始一步步学习VSOA开发】订阅发布变速器

订阅发布变速器 概念 在许多场景中&#xff0c;我们需要控制发布频率。例如&#xff0c;一个 UI 界面不能过快的接收处理信息&#xff0c;而此时发布者的发布频率又非常快。在这种场景下&#xff0c;我们需要改变发布的频率。 使用 VSOA Regulator 可以解决这个问题&#xff…

Kafka + Kraft 集群搭建教程,附详细配置及自动化安装脚本

本文主要介绍 kafka kraft 搭建过程&#xff0c;主要用途是为了日志采集&#xff0c;所以搭建相对比较简单暴力&#xff0c;不过也可以作为一个参考供大家学习&#xff0c;主打一个能用管跑&#xff08;调优啊&#xff0c;参数解释啊&#xff0c;原理啊&#xff0c;太枯燥了&a…

其实PMP考试真的不需要焦虑

在考PMP之前&#xff0c;觉得报名费好贵很可怕&#xff0c;很怕自己考不过然后3900打水漂~然后我自己慢慢悠悠跟着老师安排来&#xff0c;2个月就上岸啦~担心真的是多余的&#xff01; 问了一下培训班的小伙伴&#xff0c;好像都过了。听说PMP在国内的通过率高达90%不知道真假…

高频焊机电源模型建立及谐波分析

1、仿真建模工具 本文的仿真建模工具软件采用MATLAB7.0&#xff0c;即目前工程领域最为流行的软件。MATLAB把计算、可视化、程序设计融入到了一个交互的工作环境中&#xff0c;已经成为电力系统仿真、自动控制理论、数字信号处理、图像处理等领域的常用工具软件。MATLAB中的SIM…

解锁数据“智能”背后的秘密

在这个被数据洪流包围的时代&#xff0c;每一秒都有无数的信息在生成、传递、分析。但你是否曾好奇&#xff0c;这些数据是如何从简单的数字、文字转化为推动社会进步、改变生活方式的“智能”力量的&#xff1f;今天&#xff0c;就让我们一起揭开数据“智能”背后的神秘面纱&a…

在Excel中启用宏 (~ ̄▽ ̄)~

一、启用宏 打开任意Excel&#xff0c;点击屏幕左上角的文件选项&#xff0c;然后选择Excel选项窗口。在Excel选项窗口中&#xff0c;选择信任中心按钮&#xff1b;在信任中心设置窗口中&#xff0c;选择宏设置&#xff0c;启用所有宏&#xff08;不推荐&#xff0c;潜在风险&a…

鸿蒙OS开发使用Canvas组件绘制天气曲线图

参考下文&#xff1a; 鸿蒙征文 | 使用Canvas组件绘制天气曲线图_harmonyos_鸑鷟407-HarmonyOS开发者社区效果图&#xff1a; 原理 使用贝塞尔曲线 首先可以了解一下贝塞尔曲线。 如果看不懂也没关系&#xff0c;这里会直接讲绘制曲线的步骤。 使用CanvasRenderingContext2D对象…

VS code初学笔记

一、调试 1.1添加查看全部数组元素 监视->*(type(*)[number])begin 其中type表示类型int、char等。number表示要查看的数量。begin是起始地址指针&#xff0c;即数组名。

github使用gh-pages部署vue静态网站(简单易懂)

github使用gh-pages部署vue静态网站 当我们想把自己的网站部署到一个静态网站上&#xff0c;Github Pages是一个很好的选择&#xff08;稳定、可靠、不花钱&#xff09; 假设你已经有一个项目并且已经发布到github上了&#xff0c;先把项目git clone到本地 &#xff0c;接着在…

第二季度云计算市场份额榜单:微软下滑,谷歌上升,AWS仍保持领先

2024 年第二季度&#xff0c;随着企业云支出达到 790 亿美元的新高&#xff0c;三大云计算巨头微软、谷歌云和 AWS的全球云市场份额发生了变化。 根据新的市场数据&#xff0c;以下是 2024 年第二季度全球云市场份额结果和六大世界领先者&#xff0c;其中包括 AWS、阿里巴巴、…

条形码与二维码报表

概述 条形码与二维码&#xff1a;演示条形码与二维码&#xff0c;条形码数据将来自于关联的字段值。支持各种常用的条形码与二维码。 应用场景 如下图所示&#xff0c;简单展示数据 示例说明 数据准备 在数据面板中添加数据集&#xff0c;可选择Json数据集和API服务数据…

​全国大学分布SHP数据分享

数据是GIS的血液&#xff01; 我们在《全国地铁路线及站点SHP数据》一文中&#xff0c;为你分享过全国地铁路线及站点数据。 现在再为你分享全国大学信息分布SHP数据&#xff0c;你可以在文末查看该数据的领取方法。 全国大学分布数据 据不完全统计至2024年6月20日&#xf…

护眼落地灯十大品牌排名:2024十大值得入手的护眼落地灯盘点

2024十大值得入手的护眼落地灯是哪款&#xff1f;随着生活水平的提高&#xff0c;许多家长在关心孩子身心健康的同时也关注着孩子的视力健康&#xff0c;很多家长了解到光线对孩子视力的影响&#xff0c;都纷纷给孩子准备护眼大路灯&#xff0c;但是面对市面上众多的护眼大路灯…

Java HotSpot虚拟机中的内存管理手册阅读笔记

显示与自动内存管理 内存管理是计算机编程中的一个重要概念&#xff0c;它涉及到跟踪和控制程序使用内存的方式。内存管理可以分为两种主要类型&#xff1a;显式内存管理和自动内存管理。 显式内存管理 在显式内存管理系统中&#xff0c;程序员必须手动分配和释放内存。这通…

筒射巡飞无人机技术详解

筒射巡飞无人机&#xff08;Launch and Recovery by Tube, LRAT&#xff09;作为一种新型无人机系统&#xff0c;其机体结构设计充分考虑了便携性、隐蔽性及空气动力学效率。该无人机通常采用模块化设计&#xff0c;主体结构紧凑&#xff0c;能够适配于标准发射筒内进行发射与回…

CISP和NISP到底啥区别?网络安全行业考证必知

随着网络攻击的日益频繁和复杂化&#xff0c;信息安全专业人才的需求也随之激增。 在众多信息安全认证中&#xff0c;CISP与NISP尤为受到关注&#xff0c;不少搞安全的朋友应该都对他们有所耳闻。 但在选择认证时&#xff0c;往往又犯了难。 这两个安全认证的差别在哪里&#x…