浅析java class文件格式

我们知道AOP的生成是代理+反射,其内部是首先对AOP要处理的类进行继承,然后在要执行切面的地方的方法前或后加上其他的代码逻辑,此处就必须要进行动态的class文件生成,因为Java中万物皆对象,所以它只会处理对象,那么必然要将其生成一个新的对象。在Java中要动态生成一个class文件必须要通过classLoader的defineClass进行,此方法中需要一个bytes数组和其他的一些参数比如还需要ProtectionDomain,那么一般会传递null那么会使用默认的ProtectionDomain(这和C++默认参数不一样,C++默认参数是基本参数类型,这是对象)。

protected final Class<?> defineClass(String name, byte[] b, int off, int len,
					 ProtectionDomain protectionDomain)
	throws ClassFormatError
    {
	check();//检查ClassLoader是否被初始化,未初始化抛出未初始化异常
	protectionDomain = preDefineClass(name, protectionDomain);//决定保护域(<span style="font-family: Arial, Helvetica, sans-serif;">protectionDomain 权限控制,在此方法中生成默认值),check文件名,不能以java.</span>
开头,因为java.*的文件都是引导文件,我们不可以干预
	Class c = null;
        String source = defineClassSourceLocation(protectionDomain);//获取和CodeSource相关的位置,url是不可变的因此一般返回的是codeSource的位置

	try {
	    c = defineClass1(name, b, off, len, protectionDomain, source);//调用native方法生成class文件,native方法的具体实现与JVM相关
	} catch (ClassFormatError cfe) {
	    c = defineTransformedClass(name, b, off, len, protectionDomain, cfe, source);
	}

	postDefineClass(c, protectionDomain);//给类设置签名,调用本地方法
	return c;
    }
通过上述代码可以看到我们要想实现一个动态的类,需要去生成的主要是关于一个类的bytes数组,那么此数组来自于String,那么我们需要关注的是java的class文件格式,然后按照文件格式生成即可,目前比较成熟的jar是asm.java,有兴趣的可以读一下。 AMS5.0源码和Demo
Java字节码文件格式(学过IOSRuntime的同学有没有觉得很相似?反正我觉得很像)

   ClassFile {
    	u4 magic;
    	u2 minor_version;
    	u2 major_version;//和mimor构成VMajor.Minor,具体采用哪种由Java的JVM版本决定
    	u2 constant_pool_count;//常量池的内容是pool_count+1,大于0或小于pool_cout是有效的
    	cp_info constant_pool[constant_pool_count-1];//存储字符串常量,包括类、接口的名字,属性域的名字以及其他与类结构和子类结构相关的常量
    	u2 access_flags;//类或接口的访问权限等属性
    	u2 this_class;
    	u2 super_class;
    	u2 interfaces_count;
    	u2 interfaces[interfaces_count];//类和接口必须要在常量池有描述,并且不可超过255(因为它用一个字节表示了1-255的个数,内部实现了utf8的转码)
    	u2 fields_count;
    	field_info fields[fields_count];
    	u2 methods_count;
    	method_info methods[methods_count];//属性和方法的描述符请参考表,方法是(参数)返回值
    	u2 attributes_count;//各种信息的文件格式
    	attribute_info attributes[attributes_count];
    }
其中u2 u4分别指的是u1, u2, and u4 represent an unsigned one-, two-, or four-byte,是字节。

属性表(Flag之间是有关联的,关联的形式即类或接口的性质)


属性表的标识符


由于常量池里面保管各种信息的描述符,因此对于属性(继承的不放在本身里面)和方法以及接口方法的存放是tag+类索引(常量池表中)+nameAndType的索引(常量池表中)

其他的部分是对属性等方法的定义,有兴趣的可以看原文

关于ASM中,博主看了其中关于HelloWorld的demo,里面需要说明的是ASM通过对字节码文件进行描述来实现动态class文件生成,他的生成是生成byteArray,那么里面关于byteArray是根据class文件的文件结构定义的

PS:其中MethodWriter与ClassWriter是相互关联的对象,ClassWriter里面的firstMethod和lastMethod是method方法的管理用的是链表,他们的初始化采用的是delay方式,此种实现是在MethodWriter中进行的,通过判断是否为空进行管理。他们可以直接对firstMethod和lastMethod进行赋值而无需考虑中间是否还有其他method原因在于所有的method方法的描述会放入常量池,具体相关还请大家看上面的原文链接。英文原文内容较多,博主只是对其中的开头部分进行了说明,有想详细了解的建议读原文。






  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值