字节码编程ASM之两数之和

news2024/11/15 13:58:40

写在前面

源码 。
看下如何使用ASM来写如下的类:

package com.dahuyou.demo.asm;

public class AsmSumOfTwo {
    public AsmSumOfTwo() {
    }

    public static void main(String[] var0) {
        int var1 = (new AsmSumOfTwo()).sum(1, 2);
        System.out.println(var1);
    }

    public int sum(int var1, int var2) {
        return var1 + var2;
    }
}

1:编码

源码:

package com.dahuyou.asm.helloworld;

import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Method;

public class SumOfTwo extends ClassLoader {

    public static void main(String[] args) throws Exception {
        // 生成二进制字节码
        byte[] bytes = generate();
        // 输出字节码
        outputClazz(bytes);
        // 加载AsmHelloWorld
        Class<?> clazz = new SumOfTwo().defineClass("com.dahuyou.demo.asm.AsmSumOfTwo", bytes, 0, bytes.length);
        // 反射获取 main 方法
        Method main = clazz.getMethod("main", String[].class);
        // 调用 main 方法
        main.invoke(null, new Object[]{new String[]{}});
    }

    private static byte[] generate() {

        ClassWriter classWriter = new ClassWriter(0);

        {
            MethodVisitor mv = classWriter.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
            mv.visitCode();
            // aload指令,加载本地变量表0位置对象(a)
            mv.visitVarInsn(Opcodes.ALOAD, 0);
            // invokespecial指令,调用方法<init>
            mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
            // return指令,返回void
            mv.visitInsn(Opcodes.RETURN);
            // 操作数栈,局部变量表大小
            mv.visitMaxs(1, 1);
            mv.visitEnd();
        }

        // 定义对象头;版本号、修饰符、全类名、签名、父类、实现的接口
        classWriter.visit(Opcodes.V1_7, Opcodes.ACC_PUBLIC, "com/dahuyou/demo/asm/AsmSumOfTwo", null, "java/lang/Object", null);
        // 添加方法;修饰符、方法名、描述符、签名、异常
        MethodVisitor methodVisitor = classWriter.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null);
        // int var1 = (new AsmSumOfTwo()).sum(1, 2);中的 new AsmSumOfTwo(),即创建实例对象,并压入操作数栈栈顶
        methodVisitor.visitTypeInsn(Opcodes.NEW, "com/dahuyou/demo/asm/AsmSumOfTwo");
        // 获取操作数栈栈顶元素,并复制,重新压回,此时操作数栈栈顶有连续的两个new AsmSumOfTwo()引用
        methodVisitor.visitInsn(Opcodes.DUP);
        // 栈顶元素出栈,并调用初始化方法<init>,即默认的空构造函数
        methodVisitor.visitMethodInsn(Opcodes.INVOKESPECIAL, "com/dahuyou/demo/asm/AsmSumOfTwo", "<init>", "()V");
        // iconst 加载整数常量 1,2,并压到栈顶,此时,操作数栈元素为2,1,AsmSumOfTwo实例引用
        methodVisitor.visitInsn(Opcodes.ICONST_1);
        methodVisitor.visitInsn(Opcodes.ICONST_2);

        // int var1 = (new AsmSumOfTwo()).sum(1, 2);中的.sum(1, 2) (II)I入参两个int,返回int,函数的结果存储栈顶
        methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "com/dahuyou/demo/asm/AsmSumOfTwo", "sum", "(II)I");
        // 将栈顶元素存储到本地变量表 slot 1位置,即赋值给var1(实际程序运行过程中jvm是不关心变量名称的,因为完全不影响运行结果)
        methodVisitor.visitVarInsn(Opcodes.ISTORE, 1);
        // 获取静态属性System.out
        methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
        // 将本地变量表中slot 1位置的int变量推动到操作数栈栈顶(因为要做sout)
        methodVisitor.visitVarInsn(Opcodes.ILOAD, 1);
        // 获取栈顶元素,并作sout,这样int var1 = (new AsmSumOfTwo()).sum(1, 2);的var1就完成打印了
        // (I)V参数int,返回void
        methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(I)V");
        // 返回
        methodVisitor.visitInsn(Opcodes.RETURN);

        // 设置操作数栈的深度和局部变量的大小
        methodVisitor.visitMaxs(3, 2);
        // 方法结束
        methodVisitor.visitEnd();

        /**
         * 以下代码定义如下的函数:
         * public int sum(int i, int m) {
         *     return i + m;
         * }
         */
        MethodVisitor methodVisitor_sum = classWriter.visitMethod(Opcodes.ACC_PUBLIC, "sum", "(II)I", null, null);
        // 加载本地变量表slot 1,2位置int变量到操作数栈,并调用add指令执行加法
        methodVisitor_sum.visitVarInsn(Opcodes.ILOAD, 1);
        methodVisitor_sum.visitVarInsn(Opcodes.ILOAD, 2);
        methodVisitor_sum.visitInsn(Opcodes.IADD);
        // 返回
        methodVisitor_sum.visitInsn(Opcodes.IRETURN);
        // 设置操作数栈的深度和局部变量的大小
        methodVisitor_sum.visitMaxs(2, 3);
        methodVisitor_sum.visitEnd();

        // 类完成
        classWriter.visitEnd();
        // 生成字节数组
        return classWriter.toByteArray();
    }

    private static void outputClazz(byte[] bytes) {
        // 输出类字节码
        FileOutputStream out = null;
        try {
            out = new FileOutputStream("AsmSumOfTwo.class");
            System.out.println("ASM类输出路径:" + (new File("")).getAbsolutePath());
            out.write(bytes);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (null != out) try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}

写了非常详细的注释,看下吧,还有哪里不懂的可以留言告知。然后运行下:
在这里插入图片描述
反编译看对应的Java代码:
在这里插入图片描述

写在后面

一个多么简单的加法函数,通过底层字节码方式来编写还是挺麻烦的,只能说底层还是很复杂的,但是想要进阶,不了解底层又是不行的。所以,在这winter already coming的行业环境下,加油吧!!!

参考文章列表

JVM 虚拟机字节码指令表 。

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

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

相关文章

单段时间最优S型速度规划算法

一&#xff0c;背景 在做机械臂轨迹规划的单段路径的速度规划时&#xff0c;除了参考《Trajectory Planning for Automatic Machines and Robots》等文献之外&#xff0c;还在知乎找到了这位大佬 韩冰 写的在线规划方法&#xff1a; https://zhuanlan.zhihu.com/p/585253101/e…

ChatGPT自媒体创作秘籍:高效生成优质文章和视频

在这个信息爆炸的时代&#xff0c;自媒体已经成为人们获取信息、表达观点和分享生活的重要途径。而作为自媒体创作者&#xff0c;如何高效地生成优质内容&#xff0c;吸引更多的关注和互动&#xff0c;是每一个创作者都在思考的问题。今天&#xff0c;我将为大家分享利用ChatGP…

ComfyUI+PhotoMaker|一键创造个性化人物形象

ComfyUI和PhotoMaker&#xff0c;两款引领AI图像编辑潮流的软件&#xff0c;以其强大的功能和便捷的操作&#xff0c;深受广大艺术爱好者和专业人士的喜爱。本文将带你深入了解ComfyUI和PhotoMaker的结合使用&#xff0c;助你轻松打造个性化人物形象&#xff0c;让你的作品更加…

海富泰可直动式比例阀控制器EVRD-03C26SB-C1D24-B00

控制EVOTEK海富泰可直动式及先导式比例方向阀EVRD-03A04SA-C1D24-V00、EVRD-03C08SB-C1D24-B00、EVRD-03A16SA-C1D24-V00、EVRD-03C26SB-C1D24-B00、EVRD-05A30SA-C1D24-V00、EVRD-05C60SB-C1D24-B00、EVRD-P05A80SA-IIC1D24-B00、EVRD-P07C100SB-EEC1D24-V00、EVRD-P07A150SA-…

靠!AI绘画月入过万!是否现实?

前言 AI人工智能已经出现在了越来越多领域中&#xff0c;比如最近一段时间&#xff0c;AI绘画就受到了许多人的关注&#xff0c;一来&#xff0c;其背后隐藏的版权问题、替代性问题引发了人们的广泛讨论&#xff0c;再者&#xff0c;AI绘画在短期时间内成为了流量密码&#xf…

深度学习在蛋白质结构预测的新突破:AlphaFold、RoseTTAFold与ESMFold

在蛋白质结构预测和功能预测领域&#xff0c;基于机器学习的方法最近取得了显著的进展。特别是深度学习技术在这个领域中展现出了强大的能力&#xff0c;代表性的技术有 DeepMind 的 AlphaFold 和 RoseTTAFold。这些技术利用了大量的生物数据和先进的神经网络架构&#xff0c;极…

Java-Stream流常用方法详解

概述 Java 8引入的Stream API用于对集合&#xff08;如列表、集合等&#xff09;进行函数式操作&#xff08;如过滤、映射、规约等&#xff09;。这类流提供了一种高效且易读的方式来处理集合中的数据。 获取Stream对象的方式有哪些个? 1 Stream接口提供的: of静态方法 pu…

【Sklearn驯化-回归指标】一文搞懂机器学习中回归算法评估指标:mae、rmse等

【Sklearn驯化-回归指标】一文搞懂机器学习中回归算法评估指标&#xff1a;mae、rmse等 本次修炼方法请往下查看 &#x1f308; 欢迎莅临我的个人主页 &#x1f448;这里是我工作、学习、实践 IT领域、真诚分享 踩坑集合&#xff0c;智慧小天地&#xff01; &#x1f387; 免…

Web渗透-命令执行漏洞及常见靶场探测实战

一、概述 命令执行&#xff08;RCE&#xff09;&#xff1a;应用有时需要调用一些执行系统命令的函数&#xff0c;如php中的system,exec,shell exec,passthru,popen,proc popen等&#xff0c;当用户能控制这些函数的参数时&#xff0c;就可以将恶意系统命令拼接到正常命令中&a…

Open AI不能用了,国产大模型疯狂整活

行业开启新一轮竞争。 国产大模型公司集体出手 来活了&#xff0c;国内AI大模型市场又要热闹一阵了。 近日&#xff0c;市场消息称&#xff0c;Open AI在其官方邮件表示&#xff0c;**从7月9日开始&#xff0c;将采取额外措施阻止来自非支持国家和地区的API&#xff08;应用程…

SyntaxError: Unexpected token ‘<‘ (at chunk-vendors.fb93d34e.js:1:1)打包后页面白屏vue

本地运行一切正常&#xff0c;打包到线上&#xff0c;页面一篇空白。我确定输入路径正确。。。 控制台报错&#xff0c;我就开始百度&#xff0c;有的说清空缓存就行了&#xff0c;但我清空了还是这样。。。 然后我就去排查原因。看到页面请求js&#xff0c;但是请求的好像有点…

气膜体育馆对高度的要求—轻空间

在现代体育场馆的建设中&#xff0c;气膜体育馆以其独特的优势&#xff0c;逐渐成为人们关注的焦点。不同于传统的钢筋混凝土结构&#xff0c;气膜体育馆以其轻盈、灵活、环保的特点&#xff0c;为人们带来了全新的体育体验。在设计与建设气膜体育馆时&#xff0c;高度是一个关…

AI数据分析007:根据Excel表格数据绘制柱形图

文章目录 一、介绍二、输入内容三、输出内容一、介绍 将Excel文件中2013年至2019年间线上图书的销售额,以条形图的形式呈现,每个条形的高度代表相应年份的销售额,同时在每个条形上方标注具体的销售额数值 二、输入内容 在deepseek中输入提示词: 你是一个Python编程专家,…

线性代数|机器学习-P16矩阵A的导数

文章目录 1. 概述2. 求 d A − 1 ( t ) d t \frac{\mathrm{d}A^{-1}(t)}{\mathrm{d}t} dtdA−1(t)​3. 求 d λ ( t ) d t \frac{\mathrm{d}\lambda(t)}{\mathrm{d}t} dtdλ(t)​3.1 A 和 A T A^T AT有相同的特征值3.2 特征向量单位化3.3 求 λ ( t ) \lambda(t) λ(t) 4. 交替…

手持小风扇哪个牌子比较好?五大手持小风扇品牌推荐

随着夏季的到来&#xff0c;气温日益升高。除了空调&#xff0c;各式各样的小风扇成为当下年轻人的热门宠儿。但是市面上的种类比较多&#xff0c;很多人都不知道该怎么选择&#xff0c;因为我也是买过很多产品了&#xff0c;收获了一些经验&#xff0c;接下来就把我觉得比较好…

大模型们拿着锤子找钉钉

今年的大模型赛道&#xff0c;看不见硝烟&#xff0c;却是一个白热化的战场。 这背后是对更大场景、更大规模用户入口和先发优势的争夺。在AGI尚未到来的当下&#xff0c;行业有一个共识&#xff1a;真实场景中的大规模应用&#xff0c;是大模型价值验证和通往AGI的必由之路。…

WPS-Word文档表格分页

一、问题描述 这种情况不好描述 就是像这种表格内容&#xff0c;但是会有离奇的分页的情况。这种情况以前的错误解决办法就是不断地调整表格的内容以及间隔显得很乱&#xff0c;于是今天去查了解决办法&#xff0c;现在学会了记录一下避免以后忘记了。 二、解决办法 首先记…

一键系统重装教程:电脑重装系统,5个方法轻松恢复电脑

在日常使用电脑的过程中&#xff0c;难免会遇到系统故障、运行缓慢或者病毒感染等问题&#xff0c;重装系统成为解决这些问题的有效途径。然而&#xff0c;对于许多小伙伴来说&#xff0c;电脑重装系统似乎是一项复杂且耗时的任务。其实&#xff0c;只要掌握了正确的方法&#…

什么是港股通?港股通碎股如何进行交易佣金最低万0.8?

港股通是一种投资渠道&#xff0c;它允许符合条件的内地投资者通过内地的证券账户&#xff0c;间接地买卖在香港联合交易所上市的股票。这一机制是沪港通和深港通计划的一部分&#xff0c;旨在促进内地与香港资本市场的互联互通。 ### 港股通的特点包括&#xff1a; - 交易范…

AI大模型会有意识的出千吗?

1. 引言 1.1 研究背景&#xff0c;AI系统中的规范游戏问题 在人工智能(AI)系统的发展过程中&#xff0c;规范游戏(specification gaming)一直是一个令研究者们头疼的问题。规范游戏指的是AI系统学习到一些意想不到的行为&#xff0c;这些行为虽然能够获得高奖励&#xff0c;但…