Android开发|ASM与JAVASSIST区别在哪()

ASM与JAVASSIST区别在哪? 关于asm和Javassist是什么? ASM: ASM是一个JAVA字节码分析、创建和修改的开源应用框架。它可以动态生成二进制格式的stub类或其他代理类,或者在类被JAVA虚拟机装入内存之前,动态修改类。在ASM中提供了诸多的API用于对类的内容进行字节码操作的方法。
Javassis: Javassist是一个开源的分析、编辑和创建Java字节码的类库,可以直接编辑和生成Java生成的字节码。相对于bcel, asm等这些工具,开发者不需要了解虚拟机指令,就能动态改变类的结构,或者动态生成类。
前言:上述简单的介绍可以看出; javassit 主要类似于用java源码加反射的机制实现改变一些操作。而 asm 主要是针对字节码进行操作。
一丶ASM篇 Android开发|ASM与JAVASSIST区别在哪()
文章图片

1.ASM能做什么?

  1. ASM是一个通用的Java字节码操作和分析框架。它可以直接以二进制形式修改现有类或动态生成类。提供了通用的转换和分析算法,允许轻松地组装定制的复杂转换和代码分析工具。
  2. ASM提供了与其他字节码框架类似的功能,但它关注的是使用的简单性和性能。因为它的设计和实现尽可能的小和快,所以它非常适合在动态系统中使用。
  3. ASM是一个Java类操作工具,用于动态生成和操作Java类,这是实现可适应系统的有用技术。ASM基于一种新的方法,与现有的相似工具相比,后者包括使用“访问者”设计模式,而不显式地用对象表示被访问的树。对于大多数实际需求,这种新方法比现有的工具提供了更好的性能。
2.Java二进制(class)文件的格式
【Android开发|ASM与JAVASSIST区别在哪()】要想驾驭ASM,先要了解一下JAVA的CLASS文件格式。JAVA的CLASS文件通常是树型结构。根节点包含以下元素:
  • ConstantPool:符号表;
  • FieldInfo:类中的成员变量信息;
  • MethodInfo:类中的方法描述;
  • Attribute:可选的附加节点。
    FieldInfo节点包含成员变量的名称,诸如public,private,static等的标志。
    ConstantValue属性用来存储静态的不变的成员变量的值。
    Deprecated和Synthetic被用来标记一个成员变量是不被推荐的或由编译器生成的。
    MethodInfo节点包含方法的名称,参数的类型和和它的返回值,方法是公有的,私有的或静态的等标志。
    MethodInfo包含可选的附加属性,其中最重要的是Code属性,它包含非抽象的方法的代码。
    Exceptions属性包含方法将抛出的Exception的名称。
    Deprecated和Synthetic属性的信息同上面的FieldInfo的定义一样。
    根节点的可选属性有SourceFile,InnerClasses和Deprecated。
    SourceFile用来存储被编译成字节码的源代码文件的原始名称;
    InnerClasses存储内部类的信息。由于这些属性的存在,java 的类格式是可以扩展的,也就是说可以在一个class中 附加一些非标准的属性, java虚拟机会忽略这些不可识别的属性,正常的加载这个class。
    ConstantPool是一个由数字或字符串常量的索引组成的队列,或由此类的树的其他节点引用的,由其他对象创建的被引用常量的索引组成的队列。这个表的目标是为了减少冗余。例如,FieldInfo节点不包含节点的名称,只包含它在这一表中的索引。同样的,GETFIELD和PUTFIELD不直接包含成员变量的名称,只包含名称的索引。
二丶JAVASSIST篇
Android开发|ASM与JAVASSIST区别在哪()
文章图片

1.javassis能做什么?
  1. Javassist (Java编程助手)使操作Java字节码变得简单。它是一个用于编辑Java字节码的类库;跟其他类似的字节码编辑器不同的是,它使Java程序能够在运行时定义一个新类,并在JVM加载类文件时修改它。
  2. Javassist提供了两种级别的API:源级别和字节码级别。如果用户使用源代码级API,他们可以不需要了解Java字节码的规范的前提下编辑类文件。整个API仅使用Java语言的词汇表设计。甚至你可以以源文本的形式插入字节码中;Javassist动态编译它。另一方面,字节码级API允许用户作为编辑器直接编辑类文件。
  3. Javassist允许您检查、编辑和创建Java二进制类。
  4. Javassist并不是唯一处理字节码的库,但它有一个特别功能,使其成为一个重要的开始来尝试字节码工作:你可以使用Javassist改变一个Java类的字节码而不需要学习任何关于字节码或Java虚拟机(JVM)的体系结构。
  5. 面向切面编程:Javassist可以是一个很好的工具用于向类中添加新方法,以及在调用方和被调用方两边插入before/after/around通知。
  6. 反射:Javassist另一个应用就是运行时反射;Javassist允许Java程序使用一个元对象,该元对象控制基级别对象上的方法调用。不需要专门的编译器或虚拟机。
  7. Javassist还提供了用于直接编辑类文件的低级API。要使用此级别的API,您需要详细了解Java字节码和类文件格式,而此级别的API允许您对类文件进行任何类型的修改。
三丶Javassist对比ASM
  1. Javassist源代码级API比ASM中实际的字节码操作更容易使用
  2. Javassist在复杂的字节码级操作上提供了更高级别的抽象层。Javassist源代码级API只需要很少的字节码知识,甚至不需要任何实际字节码知识,因此实现起来更容易、更快。
  3. Javassist使用反射机制,这使得它比运行时使用Classworking技术的ASM慢。
  4. 总的来说ASM比Javassist快得多,并且提供了更好的性能。Javassist使用Java源代码的简化版本,然后将其编译成字节码。这使得Javassist非常容易使用,但是它也将字节码的使用限制在Javassist源代码的限制之内。
  5. 总之,如果有人需要更简单的方法来动态操作或创建Java类,那么应该使用Javassist API 。如果需要注重性能地方,应该使用ASM库。
四丶两者概括说明
我们常用到的动态特性主要是反射,在运行时查找对象属性、方法,修改作用域,通过方法名称调用方法等。在线的应用不会频繁使用反射,因为反射的性能开销较大。其实还有一种和反射一样强大的特性,但是开销却很低,它就是Javassit。
Javassit其实就是一个二方包,提供了运行时操作Java字节码的方法。大家都知道,Java代码编译完会生成.class文件,就是一堆字节码。JVM(准确说是JIT)会解释执行这些字节码(转换为机器码并执行),由于字节码的解释执行是在运行时进行的,那我们能否手工编写字节码,再由JVM执行呢?答案是肯定的,而Javassist就提供了一些方便的方法,让我们通过这些方法生成字节码。
类似字节码操作方法ASM。几种动态编程方法相比较,在性能上Javassist高于反射,但低于ASM,因为Javassist增加了一层抽象。在实现成本上Javassist和反射都很低,而ASM由于直接操作字节码,相比Javassist源码级别的api实现成本高很多。几个方法有自己的应用场景,比如Kryo使用的是ASM,追求性能的最大化。而NBeanCopyUtil采用的是Javassist,在对象拷贝的性能上也已经明显高于其他的库,并保持高易用性。实际项目中推荐先用Javassist实现原型,若在性能测试中发现Javassist成为了性能瓶颈,再考虑使用其他字节码操作方法做优化。
结语: 自己也是从事Android开发5年有余了;整理了一些Android开发技术核心笔记,关于更多Android开发技术点击:
免费领取《免费Android技术丶面试题纲丶核心笔记资料》]
想有收获必须有努力,知识在于积累。不进则退。

    推荐阅读