上一篇文章,我们已体验到ASM的威力,那么结合上面的代码解释ASM是怎么执行的。

ClassWriter clazzWriter = new ClassWriter(0);  

首先看下官方文档对ClassWriter的描述:

A ClassVisitor that generates classes in bytecode form. More precisely this visitor generates a byte array conforming to the Java class file format. It can be used alone, to generate a Java class "from scratch", or with one or more ClassReader and adapter class visitor to generate a modified class from one or more existing Java classes

方法的栈长度和本地变量表长度用户自己计算(???怎么算);

clazzWriter.visit(Opcodes.V1_5, Opcodes.ACC_PUBLIC, "com/sunchao/asm/HelloWorld", null, "java/lang/Object", null);  

解释下方法中参数的意思:

  • Opcodes.V1_5指定类的版本
  • Opcodes.ACC_PUBLIC表示这个类是public
  • “com/sunchao/asm/HelloWorld”类的全限定名称
  • 第一个null位置变量定义的是泛型签名,
  • “java/lang/Object”这个类的父类
  • 第二个null位子的变量定义的是这个类实现的接口
        MethodVisitor mv = clazzWriter.visitMethod(Opcodes.ACC_PUBLIC , "sayHello",
"()V" , null, null);//新增加一个方法
mv.visitCode();//启动访问字节码
//在java/lang/System上添加一个Ljava/io/PrintStream类型的字段‘out’
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
mv.visitLdcInsn("Hello World!");//将常量池中的字符串常量加载到栈顶 ,输出字符串内容
//调用java/io/PrintStream中的println()方法
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V");
mv.visitInsn(Opcodes.RETURN);//设置返回值
mv.visitMaxs(0, 0);//设置方法的栈和本地变量表的大
mv.visitEnd();//结束访问

代码中的注释,可以让我们看个大概了吧。

上面的代码中我们看到了如何使用ASM生成一个简单的JAVA类,里面使用到了很多的基本概念,比如:方法描述、引用描述等

一、类版本:

一个Java二进制的类文件,都有一个版本,因此ASM中提供了几个常量来指定一个类的版,这些常量定义在org.objectweb.asm.Opcodes接口中,如下:

// versions  

    int V1_1 = 3 << 16 | 45;
int V1_2 = 0 << 16 | 46;
int V1_3 = 0 << 16 | 47;
int V1_4 = 0 << 16 | 48;
int V1_5 = 0 << 16 | 49;
int V1_6 = 0 << 16 | 50;
int V1_7 = 0 << 16 | 51;

二、JVM内部名字:

在Java二进制文件中使用的是JVM的内部名字,而不是我们所熟悉的以“.”分割的全限定名,内部名字是以“/”替代“.”的全名,例如:java.lang.String在JVM中的内部名字是java/lang/String。在ASM中可以使用org.objectweb.asm.Type类中的静态方法getInternalName(final Class c) 来获得,如下:

public class InternalNameTransform {
public static void main(String[] args) {
System.out.println(Type.getInternalName(String.class));
System.out.println(Type.getInternalName(Integer.class));
System.out.println(Type.getInternalName(InternalNameTransform.class));
}
}

运行结果:

java/lang/String
java/lang/Integer
com/sunchao/asm/InternalNameTransform

三、类型描述:

我们知道JAVA类型分为基本类型和引用类型,在JVM中对每一种类型都有与之相对应的类型描述,如下表:

Java类型 JVM中的描述
boolean Z
char C
byte B
short S
int I
float F
long J
double D
Object Ljava/lang/Object;
int[] [I
Object[][] [[Ljava/lang/Object;

在ASM中要获得一个类的JVM内部描述,可以使用org.objectweb.asm.Type类中的getDescriptor(final Class c)方法,如下:

public class TypeDescriptors {
public static void main(String[] args) {
System.out.println(Type.getDescriptor(TypeDescriptors.class));
System.out.println(Type.getDescriptor(String.class));
} }

运行结果:

Lcom/sunchao/asm/TypeDescriptors;
Ljava/lang/String;

四、方法描述:

在Java的二进制文件中,方法的方法名和方法的描述都是存储在Constant pool中的,且在两个不同的单元里。因此,方法描述中不含有方法名,只含有参数类型和返回类型,如下:

方法描述,在类中的 方法描述,在二进制文件中的
void a(int i,float f) (IF)V
void a(Object o) (Ljava/lang/Object;)V
int a(int i,String s) (ILjava/lang/String;)I
int[] a(int[] i) ([I)[I
String a() ()Ljava/lang/String;

获取一个方法的描述可以使用org.objectweb.asm.Type.getMethodDescriptor方法,如下:

public class MethodDescriptors {
public static void main(String[] args) throws Exception {
Method m = String.class.getMethod("substring", int.class);
System.out.println(Type.getMethodDescriptor(m));
} }

运行结果:

(I)Ljava/lang/String;  

其实在org.objectweb.asm.Type类中提供了很多方法。

原文请见:http://exceptioneye.iteye.com/category/253313

再叙ASM的更多相关文章

  1. EntityFramework Core Raw Query再叙注意事项

    前言 最近一直比较忙没有太多时间去更新博客,接下来会一直持续发表相关内容博客,上一篇我们讲到了EF Core中的原始查询,这节我们再来叙述一下原始查询,本文是基于在项目当中用到时发现的问题. 话题 我 ...

  2. EntityFramework Core Raw Query再叙注意事项后续

    前言 话说通过EntityFramwork Core进行原始查询又出问题,且听我娓娓道来. EntityFramework Core Raw Query后续 当我们进行复杂查询时我们会通过原始查询来进 ...

  3. 再叙TIME_WAIT

    之所以起这样一个题目是因为很久以前我曾经写过一篇介绍TIME_WAIT的文章,不过当时基本属于浅尝辄止,并没深入说明问题的来龙去脉,碰巧这段时间反复被别人问到相关的问题,让我觉得有必要全面总结一下,以 ...

  4. [转] 再叙TIME_WAIT

    http://huoding.com/2013/12/31/316 之所以起这样一个题目是因为很久以前我曾经写过一篇介绍TIME_WAIT的文章,不过当时基本属于浅尝辄止,并没深入说明问题的来龙去脉, ...

  5. 再叙Java反射

    Java中的反射 本文为反射的基础知识部分. 能够分析类能力的程序被称为反射(reflective). 反射机制允许程序在运行时取得任何一个已知名称的class的内部信息,容许程序在运行时加载.探知. ...

  6. rhel5.8安装oracle 10g ASM

    1.所有的配置和文件系统一样 2.规划: 加了8块小盘,ASM为了实验使用asmlib驱动(rhel6不再支持asmlib驱动),裸设备的2种方法(rowdevice和udev) 三块盘使用asmli ...

  7. ASM文件系统

    1.确认数据库版本 2.个人理解的存储解决方案的发展趋势 2.1图示说明 2.2图示描述 如上图我们描述了在不同时期的IT行业(数据库)出现的存储文件系统,下面我们将分别说明: ü  裸设备:所谓裸设 ...

  8. Azure ARM (19) 将传统的ASM VM迁移到ARM VM (2)

    <Windows Azure Platform 系列文章目录> 因为我们在上一节中: Azure ARM (18) 将传统的ASM VM迁移到ARM VM (1) 已经创建了Azure V ...

  9. RAW+ASM 的RAC 安装文档

    实验平台:Oracle 10gR2 RAC + RHEL 4.0 +VMWare GSX 3.2.0 安装步骤: 1.安装前准备及OS安装配置 2.安装Oracle 10gR2 clusterware ...

随机推荐

  1. JavaWeb一小时急速入门总结反思

    0.条件一个可以开发javaee的开发工具1.配置首先需要下载tomcat,用来跑javaweb的服务器,下载后自行百度配置.然后需要servlet.jar包,其实就是一个java网络层api包2.基 ...

  2. Zabbix 单位换算

    直接举一例子,然后再举一反三: 如图: 单位B 则基数为1024(倍数) 我性能参数为KB单位,我们则把单位转换成和我们计数器 保持一致的单位即可,一致后,zabbix 后面会自己准换成自己想要的显示 ...

  3. 【转】 Git——如何将本地项目提交至远程仓库

    1.(先进入项目文件夹)通过命令 git init 把这个目录变成git可以管理的仓库 git init 2.把文件添加到版本库中,使用命令 git add .添加到暂存区里面去,不要忘记后面的小数点 ...

  4. JVM垃圾收集器整理

    概述 垃圾收集器是jvm实现内存回收的具体实现.本次分享要介绍的7种垃圾收集器的作用区域及其之间的关系如下图: 注: 如果2个垃圾收集器之间有连线,表示可以搭配使用 垃圾收集器并没有最好的,只有针对不 ...

  5. 关于t00ls的挂机脚本

    0x00 前言 今天早上发现t00ls上有人发了个挂机脚本,二十四小时刷时间以及刷Tubi. 轻轻松松升级,坐收Tubi成富翁. 代码很简单,就是带上cookie每隔一段时间(比如60秒)去请求一下某 ...

  6. Mac appium apk覆盖性安装的问题

    /Applications/Appium.app/Contents/Resources/node_modules/appium/node_modules/appium-android-driver/n ...

  7. OLEDB数据源

    title: OLEDB数据源 date: 2018-01-12 21:42:37 tags: [OLEDB, 数据库编程, VC++, 数据库] categories: windows 数据库编程 ...

  8. xss框架基础框架实现

    0x00web服务器设计 (1)tornado处理请求和Application类要编写一个Tornado应用中最多的工作是定义类继承Tornado的RequestHandler类,主要用于将特定的ur ...

  9. PHP获取DHCP分配的本机IP

    在搭建本地环境的时候,需要用到多个设备,有服务器.打印机连接接设备等.因为DHCP动态分配IP,所以每次重连都会发生IP地址的变更. 解决办法就是将每个设备的本机IP上传到统一的地方保存.因为使用RE ...

  10. 在HTML页面中获取当前项目根路径的方法

    在HTML页面获取项目根路径的方法: function getRootPath(){ var curPageUrl = window.document.location.href; var rootP ...