ASM3.0学习(一)

一、简述

用于生成和转换编译后的java类,动态生成java 字节码,生成class文件。

二、使用描述

编译后的java类包含以下几部分:
 一个用于描述修饰符(public或者private),类名,父类名称,所实现的接口名称以及类注解的段。
 一个用于描述类中字段信息的段。每个这样的段中都描述了字段的修饰符,名称,类型以及与该字段相关的注解。
 一个用于描述方法和构造方法的段。每个段描述了方法的名称,返回值,参数类型以及方法的注解。同时也包含了方法编译后的字节码序列。

在源代码和编译后的代码之间,还是存在一些不同:
 一个编译后的java类仅仅只描述一个类信息,但是一个java源文件可以包含几个java类。例如,一个源文件可以定义一个包含内部类的java类,而编译后将会成为两个类文件,其中一个是主要的java类,另外一个是内部类。在主要的类中包含了指向内部类的引用,同时在主要的java类的方法中定义的内部类也会包含一个指向该java方法的引用。
 一个编译后的java类不包含注释,当然,可以包含与类、字段、方法或者代码相关的属性,而这些属性可以用来关联一些额外的信息。在java 5中引入了注解以后,这些注解也可以实现同样的目的,因此,这些属性就变得不那么重要了。
 一个编译后的java类不包含package和import段,因此,在编译后的类中,所有的类型名称都必须使用全路径。

 

类的具体结构请参看java虚拟机规范第四段

76656d17daa4f1fbdea04b6711e55055a54.jpg

编译后的java类整体结构(*表示0或者更多)

2.1.2内部名称
在很多情况下,一个类型限于一个java类或者结构表示的类型,例如,一个类的父类,一个类所实现的接口,一个方法所抛出的异常(不可能是基本类型)或者数组,这些都是类或者接口类型。这些类型在编译后的类中以内部名称表示。一个类的内部名称就是这个类的全路径名称,将包名中的点号替换为/。例如,String的内部名称为java/lang/String。

2.1.3类型描述符
内部名称仅用作一个类或者接口的类型,所有其他的,如字段类型,java基本类型都是以类型描述符来表示的,见图2.2
 类型描述符:

50d035aad1a8b76a5979b654846e4e1cf46.jpg
基本类型的描述符:Z表示boolean,C表示char,B表示byte,I表示int,F表示float,J表示long,D表示double。一个类的描述符就是这个类的内部名称,在前面加上一个L,在后面加上一个分号即可。例如,String的类型描述符就是Ljava/lang/String.最后,一个数组的类型描述符就是一个中括号[后面跟上数组元素的类型描述符。

2.1.4方法描述符
一个方法描述符就是一个包含参数类型的描述符,以及方法返回类型描述符的字符串。一个方法描述符以一个左括号开始,然后跟上每个参数的描述符,然后是一个右括号,最后就是返回值的类型描述符,如果一个方法的返回值是void,那么返回值的类型描述符就是V(一个方法描述符不包含这个方法的名称以及参数的名称)。
方法描述符示例

3a12c3931199e8a9034a42ccd12b10c71cf.jpg
一旦你知道了类型描述符如何工作,那么理解方法描述符很容易。例如,(I)I描述了这样一个方法,它有一个int类型的参数,以及一个int返回值。图2.3给出了几个方法描述符的例子。

2.2接口和组件
2.2.1表现(Presentation)
生成和转换编译后的类的ASM API是基于ClassVisitor接口的(见图2.4)。在这个接口中的每一个方法都与类文件中有着相同名称的段相对应(见图2.1)。在访问类结构中简单的段时,是通过调用一个独立的方法来实现的,该方法的参数就是该段相关的内容,该方法的返回值为void。对长度任意并且较复杂的段进行访问时,是通过一个初始化方法返回一个辅助的visitor接口来实现,例如visitAnnotation,visitField以及visitMethod,它们都返回与之对应的接口AnnotationVisitor,FieldVisitor以及MethodVisitor。
这些规则也同样适用于这些辅助接口。例如,在FieldVisitor接口中的每个方法,都与类文件结构中与该名称(Field)对应的子结构对应(见图2.5),并且visitAnnotation并会一个辅助的AnnotationVisitor接口,与ClassVisitor中的AnnotationVisitor相同。关于这些辅助接口的创建和使用,将在下一章节介绍,这一章主要限于那些简单的问题,使用ClassVisitor接口就可以解决的。
图2.4 ClassVisitor接口

4ba1d1cdbd18e38712b2d975f91d8dd3153.jpg
图2.5 FieldVisitor接口

5e55bf15fd0dfe9279d549c263161ceefb6.jpg
对ClassVisitor接口中方法的调用必须遵循下面文档定义的顺序,该文档定义在ClassVisitor
接口的Javadoc中。
visit visitSource? visitOuterClass? ( visitAnnotation | visitAttribute )*( visitInnerClass | visitField | visitMethod )*
visitEnd
这就意味着visit必须被第一个调用,然后调用visitSource方法,最多调用一次,再接着是visitOuterClass,然后再调用任意次数的visitAnnotation或者visitAttribute方法,接着可以调用任意次数的visitInnerClass,visitiField或者visitMethod,顺序不限,在最后,调用visitEnd方法。
在ClassVisitor接口的基础上,ASM提供了三个组件来生成和转换类:
 ClassReader 用来解析编译过的class的字节数组。然后,调用ClassVisitor实例的visitXxx方法,其中ClassVisitor实例作为ClassReader.accept方法的参数传递进去的。ClassReader可以被看做是一个事件产生者。
 ClassWriter是ClassVisitor接口的一个实现,用来以二进制方式构建编译后的类。它产生一个包含编译后的类的字节数组,可以通过它的toByteArray方法来或得。它可以被看做是一个事件消费者。
 ClassAdapter也是ClassVisitor接口的一个实现,它将对它的方法调用委托给另一个ClassVisitor。它可以被认为是一个事件过滤器。
接下来,将结合具体的例子来展示如何使用这些组件来生成和转换类。

 

转载于:https://my.oschina.net/u/2292306/blog/3005519

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值