【Javassist】快速入门系列10 当检测到instanceof表达式时用代码块替换

news2024/11/20 13:22:28

系列文章目录

01 在方法体的开头或结尾插入代码
02 使用Javassist实现方法执行时间统计
03 使用Javassist实现方法异常处理
04 使用Javassist更改整个方法体
05 当有指定方法调用时替换方法调用的内容
06 当有构造方法调用时替换方法调用的内容
07 当检测到字段被访问时使用语句块替换访问
08 当检测到对象(不包括数组)创建时用代码块替换
09 当检测到对象(不包括数组)创建时用代码块替换
10 当检测到instanceof表达式时用代码块替换


文章目录

  • 系列文章目录
  • 前言
  • 引入Javassist jar包
    • 当检测到instanceof表达式时用代码块替换
  • 总结
  • 说明


前言

上一章我们介绍了当检测到数组创建时用代码块替换,学习了 method.instrument的用法。以及参数为NewArray 的重载方法edit的含义。本章主要介绍当检测到instanceof表达式时用代码块替换。


引入Javassist jar包

在上几篇文章已经引入了javassist的jar包,如果你是第一次观看本系列文章,也可以复制以下maven依赖将jar包导入工程。

        <dependency>
            <groupId>org.javassist</groupId>
            <artifactId>javassist</artifactId>
            <version>3.28.0-GA</version>
        </dependency>

当检测到instanceof表达式时用代码块替换

/**
 * 【Javassist】快速入门系列10 当检测到instanceof表达式时用代码块替换
 * 公众号&B站:精致的王同学
 * @author wangfengxi1
 * @date 2022/12/27 17:29
 */
public class Basic10Instanceof {
    public static void main(String[] args) throws Exception{
        //获取javassist默认类池
        ClassPool pool = ClassPool.getDefault();
        // 获取basic.Basic10Test类的ctClass文件
        CtClass ctClass = pool.get("basic.Basic10Test");
        // 获取basic.Basic10Test类的main方法
        CtMethod method = ctClass.getDeclaredMethod("main");
        // 当检测到instanceof表达式时用代码块替换
        method.instrument(new ExprEditor(){
            @Override
            public void edit(Instanceof i) throws CannotCompileException {
                try {
                    CtClass type = i.getType();
                    if (type.equals(pool.get("domain.Animal"))) {
                        i.replace("$_=$proceed($$);System.out.println(\"Instanceof,result:\"+$_+\";value:\"+$1);");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        // 获取修改后的class文件
        Class<?> clazz = ctClass.toClass();
        // 获取修改后的实例对象
        Object obj = clazz.newInstance();
        // 获取修改后的main方法
        Method main = clazz.getDeclaredMethod("main", String[].class);
        // 调用修改后的main方法
        main.invoke(obj,(Object) new String[0]);
    }
}

以上Basic10Instanceof 类创建了一个main方法,该方法中首先获取javassist的类池pool,然后调用pool.get(“basic.Basic10Test”)方法获取到basic包下的Basic10Test类。Basic10Test类源码如下:

/**
 * 第10节测试类
 *
 * @author wangfengxi1
 * @date 2022/12/27 17:31
 */
public class Basic10Test {
    public static void main(String[] args) {
        People people = new People(1,"人");
        if (people instanceof Animal) {
            System.out.println(people.toString());
        }
    }
}

该类中有一个main方法,创建了一个People对象。然后判断people是否是Animal类或者其子类。如果是则在屏幕打印people对象。其中People类的源码如下:

/**
 * 人
 *
 * @author wangfengxi1
 * @date 2022/12/27 17:35
 */
public class People extends Animal{
    public People(Integer type, String typename) {
        super(type, typename);
    }
}

People继承了Animal类,其中Animal类的源码如下:

/**
 * 动物父类
 *
 * @author wangfengxi1
 * @date 2022/12/27 17:34
 */
public class Animal {
    private Integer type;
    private String typename;

    public Animal(Integer type, String typename) {
        this.type = type;
        this.typename = typename;
    }

    public Integer getType() {
        return type;
    }

    public void setType(Integer type) {
        this.type = type;
    }

    public String getTypename() {
        return typename;
    }

    public void setTypename(String typename) {
        this.typename = typename;
    }

    @Override
    public String toString() {
        return "Animal{" +
                "type=" + type +
                ", typename='" + typename + '\'' +
                '}';
    }
}

回到Basic10Instanceof 的main方法,在获取到Basic10Test 类的ctClass的对象之后,获取其main方法的方法对象。

接着调用method.instrument(ExprEditor editor)方法搜索method内的instanceof表达式。调用i.getType()方法获取instanceof表达式类型,判断如果是domain.Animal的ctClass文件则调用i.replace(“ = _= =proceed($ ) ; S y s t e m . o u t . p r i n t l n ( I ¨ n s t a n c e o f , r e s u l t : + ¨ );System.out.println(\"Instanceof,result:\"+ );System.out.println(I¨nstanceof,result:+¨_+”;value:“+$1);”);表示替换instanceof表达式。

instrument方法接收一个ExprEditor 类型的对象,该类有很多重载的edit方法,其中参数为Instanceof 的重载方法代表搜索方法内的instanceof表达式。

在replace的代码块中,以下符号有特殊含义:

$0  null。
$1  原始instanceof运算符左侧的值。
$_  表达式的结果值。$_的类型是布尔型。
$r  instanceof运算符右侧的类型。
$type  表示instanceof运算符右侧类型的java.lang.Class对象。
$proceed  执行原始instanceof表达式的虚拟方法的名称。它接受一个参数(类型为java.lang.Object)并且如果参数值是instanceof操作符右侧类型的实例的话返回true。否则,返回false

最后模拟调用修改后的main方法结果如下:
main方法结果

总结

本篇文章介绍了使用Javassist当检测到instanceof表达式时用代码块替换,学习了 method.instrument的用法。以及参数为Instanceof的重载方法edit的含义。

说明

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

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

相关文章

Android核心技术——Jetpack Hilt依赖注入

依赖注入是什么 个人理解&#xff1a;把有依赖关系的类放在容器中&#xff0c;解析这些类的实例&#xff0c;并在运行时注入到对应的字段中&#xff0c;就是依赖注入&#xff0c;目的是为了类的解耦 例子&#xff1a;A 类 中用到了 B 类&#xff0c;一般情况下需要在 A 类中 …

Promise:工作流程、常见API、使用方法、手撕Promise、async/await

Promise和axios一、Promise的常见骚操作0.初体验1.使用Promise封装原生AJAX2.Promise实例对象的两个属性&#xff08;1&#xff09;状态属性PromiseState&#xff08;2&#xff09;结果值属性PromiseResult3.Promise的工作流程4.Promise的API&#xff08;1&#xff09;.then和.…

ceph--理论

分布式存储--------Ceph 前言&#xff1a;随着OpenStack的快速发展&#xff0c;给Ceph的发展注入了强心剂&#xff0c;越来越多的人使用Ceph作为OpenStack的底层共享存储&#xff0c;Ceph在中国的社区也蓬勃发展起来。近两年OpenStack火爆度不及当年&#xff0c;借助于云原生尤…

SoringBoot+VUE前后端分离项目学习笔记 - 【01 环境配置以及VUE2集成ElementUI】

技术栈一览 SpringBoot2 Vue2 ElementUI Axios Hutool Mysql Echarts 所需软件环境 版本一览 JDK 1.8Mysql5.7Node 14.16.0navicatIdea 2021 Vue-cli 安装 npm install -g vue/cli 查看版本 创建VUE工程 初始化工程 vue create vue 选择Manually select feature…

【MySQL】数据库索引 - 浅谈索引类型

索引类型可以分为哈希表、有序数组和 N 叉树 不管是哈希还是有序数组&#xff0c;或者 N 叉树&#xff0c;它们都是基于其自身数据结构的特性来提高读写速度。在 NoSQL 里面还运用到了 LSM 树&#xff0c;来提高写的速度&#xff0c;还有跳表等数据结构来进行优化。 不过需要…

数据结构与算法-java

什么是数组&#xff1f; &#xff08;1&#xff09;数组是计算机中最基本的数据结构之一&#xff0c;我们会用一些名为索引的数字来标识每项数据在数组中的位置。 &#xff08;2&#xff09;大多数编程语言中索引是从0开始的。 &#xff08;3&#xff09;数组在内存中是存在连续…

如何打造一个流式数据湖

Flink将数据写入到 hudi 准备阶段 启动hadoop集群&#xff08;单机模式&#xff09; ./sbin/start-all.shhdfs离开安全模式 hdfs dfsadmin -safemode leave启动hive 后台启动元数据 ./hive --service metastore &启动hiveserver2 ./hiveserver2 &执行sql语句之前…

fpga实操训练(ip rom)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 altera的fpga本身自带了rom的ip&#xff0c;使用起来也十分方便。实际开发中&#xff0c;使用rom的场景也很多&#xff0c;比如一些默认的配置文件…

TensorFlow之回归模型-2

1 基本概念 回归模型 线性 线性模型 非线性模型 线性回归 逻辑回归 Log Loss&#xff08;损失函数&#xff09; 分类临界值 2 效率预测 回归问题是预测一个持续的值&#xff0c;主要是用于解决不确定性的问题&#xff0c;例如&#xff0c;一个商品在未来可能的价格或…

CMAKE_INSTALL_PREFIX

一、定义 CMAKE_INSTALL_PREFIX为cmake的内置变量&#xff0c;用于指定cmake执行install命令时&#xff0c;安装的路径前缀。Linux下的默认路径是/usr/local &#xff0c;Windows下默认路径是 C:/Program Files/${PROJECT_NAME} 二、用…

dcloud如何苹果ios系统真机测试-HBuilderX真机运行ios测试

dcloud如何运行到IOS真机测试 1&#xff0c;下载安装iTunes 安装完毕后重新打开HBuilderX 2&#xff0c;点击运行真机 将iPhone 与电脑进行链接&#xff0c;点信任&#xff0c; 运行-运行到手机或模拟器-运行到IOS APP 基座 安装过itunes就会有显示&#xff0c;但是这里还有…

进程的学习 —— Linux下的进程

目录前言1 认识进程1.1 进程的概念1.2 进程的管理1.3 查看进程的两种方法1.4 getpid、getppid和fork函数2 进程状态2.1 普遍概念下的进程状态2.2 Linux下的进程状态2.2.1 测试Linux的各种进程状态2.2.2 僵尸进程2.3 孤儿进程3 进程切换与进程优先级3.1 并行、并发3.2 进程切换3…

kafka和sparkStreaming

1、Kafka 1、kafka集群架构 producer 消息生产者&#xff0c;发布消息到Kafka集群的终端或服务 broker Kafka集群中包含的服务器&#xff0c;一个borker就表示kafka集群中的一个节点 topic 每条发布到Kafka集群的消息属于的类别&#xff0c;即Kafka是面向 topic 的。 更通俗…

HDFS 常用命令

一、HDFS常用命令 1、查看版本 hdfs version 2、创建 HDFS 文件系统目录。 格式&#xff1a; hdfs dfs -mkdir /user/dir1 3、列出目录下的所有文件 类似 Linux Shell 的 ls 命令。用它可以列出指定目录下的所有文件 hdfs dfs -ls /user/ 4、把本地文件系统文件和目录拷贝…

整合Tkinter GUI界面的古诗词词云生成

Python语言提供的wordcloud词云功能&#xff0c;使文本数据的可视化&#xff0c;简单而美丽。但网上的大多数词云生成功能&#xff0c;多半没有可交互的GUI界面&#xff0c;使用起来稍觉不便。笔者结合网上的中文词云功能&#xff0c;以唐诗三百首&#xff0c;宋词三百首&#…

拟合算法(模型+代码)

拟合的结果是得到一个确定的曲线 最小二乘法的几何解释&#xff1a; argmin 存在参数k&#xff0c;b使括号里的值最小 第一种有绝对值&#xff0c;不易求导&#xff08;求导在求最小值&#xff09;&#xff0c;计算较为复杂&#xff1b;所以我们往往使用第二种定义&#xff0…

什么软件可以录屏?这3款宝藏录屏软件,码住收藏

当我们处理剪辑视频时&#xff0c;我们需要使用到很多素材。有些素材我们可以直接从电脑网上进行下载。但有些素材我们在网上无法进行下载&#xff0c;这个时候就需要使用录屏软件进行录屏。什么软件可以录屏&#xff1f;今天小编向您分享3个宝藏录屏软件&#xff0c;赶紧码住收…

jmeter基础使用方法

文章目录一 配置环境变量二 Jmeter默认语言设置三 启动线程组的创建发送http请求数据报告一 配置环境变量 设置JMETER_HOME,及jemeter解压目录。 设置CLASSPATH,此处分别配置ApacheJMeter_core.jar和jorphan.jar所在位置。 关于环境变量配置多个值&#xff0c;在多个参数中间…

动态规划——状态压缩dp

文章目录概述状态压缩使用条件状压dp位运算棋盘&#xff08;基于连通性&#xff09;类问题概述例题蒙德里安的梦想小国王玉米田炮兵阵地集合类问题概述例题最短Hamilton路径愤怒的小鸟总结概述 状态压缩 状态压缩就是使用某种方法&#xff0c;简明扼要地以最小代价来表示某种…

MySQL 进阶篇2.0 存储过程 触发器 锁 InnoDB引擎

45.存储过程-介绍 46.存储过程-基本语法 -- 查看 select * from information_sc