使用javassist生成新类

2023-10-29

javassist

javassist是一个开源的分析、编辑和创建Java字节码的类库。不需要了解虚拟机指令,就能动态生成类或者改变类的结构。

ClassPool

ClassPool是缓存CtClass对象的容器,所有的CtClass对象都在ClassPool中。所以,CtClass对象很多时,ClassPool会消耗很大的内存,为了避免内存的消耗,创建ClassPool对象时可以使用单例模式,或者对于CtClass对象,调用detach方法将其从ClassPool中移除。

创建ClassPool对象

构造函数1

public ClassPool()

创建一个根ClassPool对象

构造函数2

public ClassPool(boolean useDefaultPath)  

创建一个根ClassPool对象,当参数为true时,appendSystemPath将被调用。

构造函数3

public ClassPool(ClassPool parent)  

创建一个指定根的ClassPool对象,若无根,则参数为null。

单例

public static ClassPool getDefault()  

创建默认的ClassPool对象,该方法是单例的。当调用该方法时,等同于下面代码的调用。

ClassPool cp = new ClassPool(); cp.appendSystemPath();  

修改生成的类

首先生成一个类

public class ClassGeneratedByJavassist {  

    public static void main(String[] args) throws Exception {  

        ClassPool pool = ClassPool.getDefault();  

        CtClass ctClass = pool.makeClass("com.study.javassist.MyCC");  

        // 添加一个参数  
        CtField ctField = new CtField(CtClass.intType, "id", ctClass);  
        ctField.setModifiers(Modifier.PUBLIC);  
        ctClass.addField(ctField);  

        // 把生成的class文件写入文件  
        byte[] byteArr = ctClass.toBytecode();  
        FileOutputStream fos = new FileOutputStream(new File("D://MyCC.class"));  
        fos.write(byteArr);  
        fos.close();  
        System.out.println("over!!");  
    }  
}  

通过XJad反编译,结果如下:

package com.study.javassist;  


public class MyCC  
{  

    public int id;  

    public MyCC()  
    {  
    }  
}  

下面对MyClass.Java再添加一个name属性,如下:

public class ClassGeneratedByJavassist {  

 public static void main(String[] args) throws Exception {  

        ClassPool pool = ClassPool.getDefault();  

        CtClass ctClass = pool.makeClass("com.study.javassist.MyCC");  

        // 添加一个参数  
        CtField ctField = new CtField(CtClass.intType, "id", ctClass);  
        ctField.setModifiers(Modifier.PUBLIC);  
        ctClass.addField(ctField);  

        // 把生成的class文件写入文件  
        byte[] byteArr = ctClass.toBytecode();  
        FileOutputStream fos = new FileOutputStream(new File("D://MyCC.class"));  
        fos.write(byteArr);  
        fos.close();  
        System.out.println("over!!");  

        // 为了测试ctClass是否能够再修改,再添加一个域  
        CtField ctField2 = new CtField(pool.get("java.lang.String"), "name",  
                ctClass);  
        ctField2.setModifiers(Modifier.PUBLIC);  
        ctClass.addField(ctField2);  
        byteArr = ctClass.toBytecode();  
        fos = new FileOutputStream(new File("D://MyCC.class"));  
        fos.write(byteArr);  
        fos.close();  
        System.out.println(1111);  
    }  
}  

当执行时,抛出如下异常:

Exception in thread "main" java.lang.RuntimeException: com.study.javassist.MyCC class is frozen  
    at javassist.CtClassType.checkModify(CtClassType.java:286)  
    at javassist.CtField.setModifiers(CtField.java:239)  
    at com.study.javassist.ClassGeneratedByJavassist.main(ClassGeneratedByJavassist.java:36)  

原因解释如下
当CtClass对象通过writeFile()、toClass()、toBytecode()转化为Class后,Javassist冻结了CtClass对象,因此,JVM不允许再次加载Class文件,所以不允许对其修改。
因此,若想对CtClass对象进行修改,必须对其进行解冻,通过defrost()方法进行,如下所示:

public class ClassGeneratedByJavassist {  

    public static void main(String[] args) throws Exception {  

        ClassPool pool = ClassPool.getDefault();  

        CtClass ctClass = pool.makeClass("com.study.javassist.MyCC");  

        // 添加一个参数  
        CtField ctField = new CtField(CtClass.intType, "id", ctClass);  
        ctField.setModifiers(Modifier.PUBLIC);  
        ctClass.addField(ctField);  

        // 把生成的class文件写入文件  
        byte[] byteArr = ctClass.toBytecode();  
        FileOutputStream fos = new FileOutputStream(new File("D://MyCC.class"));  
        fos.write(byteArr);  
        fos.close();  
        System.out.println("over!!");  

        // 解冻CtClass对象  
        <span style="color:#ff0000;"><strong>ctClass.defrost();  
</strong></span>          
        // 为了测试ctClass是否能够再修改,再添加一个域  
        CtField ctField2 = new CtField(pool.get("java.lang.String"), "name",  
                ctClass);  
        ctField2.setModifiers(Modifier.PUBLIC);  
        ctClass.addField(ctField2);  
        byteArr = ctClass.toBytecode();  
        fos = new FileOutputStream(new File("D://MyCC.class"));  
        fos.write(byteArr);  
        fos.close();  
        System.out.println(1111);  
    }  
}  

通过反编译,结果如下:

package com.study.javassist;  


public class MyCC  
{  

    public int id;  
    public String name;  

    public MyCC()  
    {  
    }  
}  

类名操作

获取类名

ClassPool pool = ClassPool.getDefault();  
CtClass ctClass = pool.makeClass("com.study.javassist.MyCC");  
System.out.println(ctClass.getName());  

结果如下:

com.study.javassist.MyCC  

改变类名

ctClass.setName("com.study.javassist.MyCC2");  
System.out.println(ctClass.getName());  

结果:

com.study.javassist.MyCC2  

通过重命名冻结类定义新类

当CtClass对象通过writeFile( )或者toBytecode( )方法转为class文件后,javassist不允许对CtClass对象作后续修改,因此当通过调用setName修改类名时是不允许的。
可以通过ClassPool的getAndRename(oldName, newName)方法实现。
如下示例:

  ClassPool pool = ClassPool.getDefault();  
CtClass ct1 = pool.get("com.study.javassist.TestName");  
System.out.println(ct1.getName());  
ct1.writeFile();  
CtClass ct2 = pool.getAndRename("com.study.javassist.TestName", "com.study.javassist.TestName2");  
System.out.println(ct2.getName());  

结果如下:

com.study.javassist.TestName  
com.study.javassist.TestName2  

javassist、ASM 对比

  1. javassist是基于源码级别的API比基于字节码的ASM简单。
  2. 基于javassist开发,不需要了解字节码的一些知识,而且其封装的一些工具类可以简单实现一些高级功能。比如HotSwaper。
  3. ASM比javassist性能更快,灵活行也较高。
  4. javassist提供者动态代理接口最慢,比JDK自带的还慢

参考:
http://blog.csdn.net/yyywyr/article/details/16984335
http://blog.csdn.net/z69183787/article/details/39343259
http://wsmajunfeng.iteye.com/blog/1912983

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用javassist生成新类 的相关文章

  • Java - 因内存不足错误而关闭

    关于如何最好地处理这个问题 我听到了非常矛盾的事情 并且陷入了以下困境 OOME 会导致一个线程崩溃 但不会导致整个应用程序崩溃 我需要关闭整个应用程序 但不能 因为线程没有剩余内存 我一直认为最佳实践是让它们离开 这样 JVM 就会死掉
  • NoInitialContextException:heroku 战争部署

    我一直在开发一个 J2EE 项目 并且在其中使用连接池 也通过部署在 heroku 上的数据库进行访问 我使用以下代码来设置 Connection 对象 Context initContext new InitialContext Cont
  • 获取文件的锁

    我想在对特定文件开始 threo read 时获取文件上的锁定 以便其他应用程序无法读取已锁定的文件并希望在线程终止时释放锁定文件 您可以获得一个FileLock https docs oracle com javase 8 docs ap
  • Java 7 默认语言环境

    我刚刚安装了 jre7 我很惊讶地发现我的默认区域设置现在是 en US 对于jre6 它是de CH 与jre7有什么不同 默认区域设置不再是操作系统之一吗 顺便说一句 我使用的是Windows7 谢谢你的回答 编辑 我已经看到了语言环境
  • 如何在 Openfire 中使用 smack

    你好 我计划开发一个可以连接到 gtalk facebook 等的聊天客户端 我决定将 smack API 与 openfire 一起使用 但我需要很少的指导来了解如何将它与 openfire 服务器一起使用 openfire 是否提供了基
  • Logback:SizeAndTimeBasedRollingPolicy 不遵守totalSizeCap

    我正在尝试以一种方式管理我的日志记录 一旦达到总累积大小限制或达到最大历史记录限制 我最旧的存档日志文件就会被删除 当使用SizeAndTimeBasedRollingPolicy在 Logback 1 1 7 中 滚动文件追加器将继续创建
  • 为什么Iterator接口没有add方法

    In IteratorSun 添加了remove 方法来删 除集合中最后访问的元素 为什么没有add方法来向集合中添加新元素 它可能对集合或迭代器产生什么样的副作用 好的 我们开始吧 设计常见问题解答中明确给出了答案 为什么不提供 Iter
  • 如何检测图像是否像素化

    之前有人在 SO 上提出过这样的问题 在Python中检测像素化图像 https stackoverflow com questions 12942365 detecting a pixelated image in python还有关于q
  • 如何使用正则表达式验证 1-99 范围?

    我需要验证一些用户输入 以确保输入的数字在 1 99 范围内 含 这些必须是整数 Integer 值 允许前面加 0 但可选 有效值 1 01 10 99 09 无效值 0 007 100 10 5 010 到目前为止 我已经制定了以下正则
  • 在 Java 中通过 XSLT 分解 XML

    我需要转换具有嵌套 分层 表单结构的大型 XML 文件
  • 通过 appassembler-maven-plugin 生成的脚本无法在 Spring Boot 应用程序中找到主类

    我使用 appassembler maven plugin 生成的启动脚本有问题 我有一个基本的 spring boot 应用程序 只有一个类 SpringBootApplication public class ScriptDemoApp
  • 避免 Java 中的重复导入:继承导入?

    有没有办法 继承 导入 Example 常见枚举 public enum Constant ONE TWO THREE 使用此枚举的基类 public class Base protected void register Constant
  • 如何处理 StaleElementReferenceException

    我正在为鼠标悬停工作 我想通过使用 for 循环单击每个链接来测试所有链接的工作条件 在我的程序中 迭代进行一次 而对于下一次迭代 它不起作用并显示 StaleElementReferenceException 如果需要 请修改代码 pub
  • 何时在 hibernate 中使用 DiscriminatorValue 注解

    在 hibernate 中使用 DiscriminatorValue 注释的最佳场景是什么以及何时 这两个链接最能帮助我理解继承概念 http docs oracle com javaee 6 tutorial doc bnbqn html
  • 使用 JFreeChart 为两个系列设置不同的 y 轴

    我正在使用 JFreeChart 使用折线图绘制两个数据系列 XYSeries 复杂的因素是 其中一个数据系列的 y 值通常远高于第二个数据系列的 y 值 假设第一个系列的 y 值约为数百万数量级 而第二个数据系列的 y 值约为数百万数量级
  • 检查应用程序是否在 Android Market 上可用

    给定 Android 应用程序 ID 包名称 如何以编程方式检查该应用程序是否在 Android Market 上可用 例如 com rovio angrybirds 可用 而 com random app ibuilt 不可用 我计划从
  • ArrayList.clear() 和 ArrayList.removeAll() 有什么区别?

    假如说arraylist定义为ArrayList
  • 如何使用通配符模拟泛型方法的行为

    我正在使用 EasyMock 3 2 我想基于 Spring Security 为我的部分安全系统编写一个测试 我想嘲笑Authentication http docs spring io autorepo docs spring secu
  • 基于 Spring Boot 的测试中的上下文层次结构

    我的 Spring Boot 应用程序是这样启动的 new SpringApplicationBuilder sources ParentCtxConfig class child ChildFirstCtxConfig class sib
  • 即使调整大小,如何获得屏幕的精确中间位置

    好的 这个问题有两部分 当我做一个JFrame 并在其上画一些东西 即使我将宽度设置为 400 并使其在一个项目击中它时 当然 允许项目宽度 它会反弹回来 但由于某种原因 它总是偏离屏幕约 10 个像素 有没有办法解决这个问题 或者我只需要

随机推荐

  • java 包扫描器

    java 包扫描器 扫描指定包下的所有java文件 并返回class数组 直接上代码 import java io File import java net URISyntaxException import java net URL im
  • 【Linux】gcc编译过程、make和makefile的概念与区别、Linux简单进度条实现

    文章目录 1 gcc编译过程 1 1预处理 1 2编译 1 3汇编 1 4链接 2 自动化构建工具 make和makefile 2 1使用背景 2 2两者的概念和区别 2 3项目清理 3 Linux简单进度条的实现 1 gcc编译过程 1
  • ubuntu安装qt

    ubuntu安装qt 第一步 下载安装包https download qt io archive qt 5 14 5 14 2 第二步 更改权限 sudo chmod x qt opensource linux x64 5 12 12 ru
  • JS中使用正则表达式g模式和非g模式的区别

    g是global的缩写啊 就是匹配全部可匹配结果 如果你不带g 在正则过程中 字符串是从左至右匹配的 如果匹配成功就不再继续向右匹配了 如果你带g 它会重头到尾的把正确匹配的字符串挑选出来 例如 1 2 3 4 5 var str aaaa
  • C++ std::vector删除元素的几种方式及区别

    容器vector在删除过程中 常用的函数 函数 作用 pop back 删除 vector 容器中最后一个元素 该容器的大小 size 会减 1 但容量 capacity 不会发生改变 erase iter 删除 vector 容器中ite
  • 机器学习——Kmeans聚类算法

    目录 简介 手肘法 手肘法核心思想 轮廓系数 代码举例1 代码举例2 实例 简介 K均值聚类算法是先随机选取K个对象作为初始的聚类中心 然后计算每个对象与各个种子聚类中心之间的距离 把每个对象分配给距离它最近的聚类中心 聚类中心以及分配给它
  • Qt之对话框设计——利用QPalette改变控件颜色

    QPalette类相当于对话框或控件的调色板 它管理着控件或窗体的所有颜色信息 每个窗体或控件都包含一个QPalette对象 在显示时按照它的QPalette对象中对各部分各状态下的颜色的描述来进行绘制 QPalette类有两个基本的概念
  • 【数学建模】混合整数规划MIP(Python+Gurobi代码实现)

    目录 1 概述 2 入门算例 2 1 算例 2 2 求解 Pulp库和cvxpy 3 进阶算例 3 1 算例 3 2 Python Gurobi代码实现 3 3 运行结果 1 概述 混合整数规划 MIP 是 NP hard 问题中的一类 它
  • ASP.NET MVC 之View相关

    VS2015 新建一个MVC工程 验证改成No Authentication 界面大致如下 得到一个解决方案如下 下面分析一下View ViewBag Title ViewPageOne Layout Views Shared Layout
  • 什么是数据挖掘,给出一个你在生活中应用数据挖掘技术的例子,分析数据挖掘的意义。...

    数据挖掘是指从大量数据中自动或半自动地发现有用的信息 模式和知识的过程 数据挖掘通常包括预处理数据 选择适当的数据挖掘技术 应用算法和模型 评估结果和解释发现的知识 一个我在生活中应用数据挖掘技术的例子是使用社交媒体平台的推荐算法 社交媒体
  • 【SQL触发器】类型 FOR 、AFTER、 Instead of到底是什么鬼

    前言 上一篇博客 博客连接 https blog csdn net jerry11112 article details 82924714 讲述了触发器的基本概念 触发器什么时候用 为什么用 这篇博客将简述触发器的类型 由于FOR触发器与A
  • GD32F330搭建工程记录: cannot open source input file “RTE_Components.h“: No such file or director

    有网友提出了解决方案 GD32F103搭建工程记录 cannot open source input file RTE Components h No such file or director 但没有确认原因 因此对此解决方案不是很满意
  • push代码时git did not exit cleanly (exit code 1).

    先缓存代码 stash changes 接着将代码拉下来 最后在把缓存读回去
  • 全力冲unreal了

    顺利辞职 其实 自己没想象中的那么重要 哈哈 交接清楚了 自然就批准离职了 以前种种 已成过往云烟 如今 再次全职unreal 再次两万五 该雪耻了 两年前的今天 好像也是全职unreal 两万五 哈哈 自以为这次准备充足了 全力冲就是了
  • 抽象类,接口,以及两者的区别

    1抽象类 含有abstract修饰符的class即为抽象类 abstract 类不能创建的实例对象 含有abstract方法的类必须定义为abstract class abstract class类中的方法不必是抽象的 abstract c
  • Python Mako

    git clone https bitbucket org zzzeek mako git Mako是用python语言开发的开源模板引擎 功能很强大 使用起来也很方便 下面介绍一下安装步骤 下载 请到官方网站http www makote
  • vue项目国际化 vue-i18n以及踩坑解决 小姐姐手把手教你VUE国际化~

    1 安装配置 安装 npm install vue i18n 或者 import VueI18n from vue i18n Vue use VueI18n 通过插件的形式挂载 const i18n new VueI18n locale z
  • 5分钟搞懂池化的本质

    大家好啊 我是董董灿 在很多与计算机视觉相关的神经网络中 我们往往都会看到池化这一算法 它一般跟在卷积层后面 神经网络中用到最多的池化方式无外乎是最大池化和平均池化 两者运算接近 区别在于是在kernel范围内取最大值还是取平均值来作为池化
  • docker-compose安装jenkins

    一 下载安装docker compose 拉取docker compose curl L https get daocloud io docker compose releases download 1 22 0 docker compos
  • 使用javassist生成新类

    javassist javassist是一个开源的分析 编辑和创建Java字节码的类库 不需要了解虚拟机指令 就能动态生成类或者改变类的结构 ClassPool ClassPool是缓存CtClass对象的容器 所有的CtClass对象都在