初衷是对反射的使用和字节码了解后,产生了想探究更深层次的原理,这就绕不过对源码的分析。了解后,发现对源码的分析可以分为两块:
- 源码和字节码的对应关系。
- 运行时反射机制的调用。
想要更深刻理解,最好先了解字节码知识
,jvm类的加载机制
。
一、如何使用反射
官方教程
使用看官网的教程就可以,大概描述下。
首先java中的任何对象,加载进jvm,都有一个对应的Class
对象(和对象存在映射关系)。教程分了如下几步
- 如何取出对象的
Class
,比如使用getClass()
函数 - 对象的成员,可以分为
Field
,method
,constructors
。如何获取对象的成员并如何使用。 - 特殊类型:
数组
和枚举
。
看完教程,恭喜你学会了使用反射机制。
二、源码与字节码
从源码出发,一层一层的讲解。探究是如何从字节码出发,看java代码是如何编排字节码,最终实现了反射
这个功能。
2.1 字节码知识
想更一步了解的可以参考,这里只是简单说明必要的。
字节码知识 & 《深入理解jvm字节码》
.java
编译后的文件.class
的内容是一个表结构
速记 | 类型 | 名称 | 说明 | 长度 |
---|---|---|---|---|
my | u4 | magic | 魔数,识别Class文件格式 | 4个字节 |
very | u2 | minor_version | 副版本号 | 2个字节 |
u2 | major_version | 主版本号 | 2个字节 | |
cute | u2 | constant_pool_count | 常量池计算器 | 2个字节 |
cp_info | constant_pool | 常量池 | n个字节 | |
animal | u2 | access_flags | 访问标志 | 2个字节 |
turn | u2 | this_class | 类索引 | 2个字节 |
savage | u2 | super_class | 父类索引 | 2个字节 |
in | u2 | interfaces_count | 接口计数器 | 2个字节 |
u2 | interfaces | 接口索引集合 | 2个字节 | |
full | u2 | fields_count | 字段个数 | 2个字节 |
field_info | fields | 字段集合 | n个字节 | |
moon | u2 | methods_count | 方法计数器 | 2个字节 |
method_info | methods | 方法集合 | n个字节 | |
areas | u2 | attributes_count | 附加属性计数器 | 2个字节 |
attribute_info | attributes | 附加属性集合 | n个字节 |
my very cute animal turn savage in full moon areas
速记类文件结构
2.1 类的组成
这是 java.lang.reflect
类的继承关系。不难看出设计上Field
,method
,constructors
等核心成员,继承于一些顶层的类AnnotatedElement
,type
等,需要先讲这些类。
2.1.1 辅助类
2.1.1.1 AnnotatedElement
作用就是运行时获取注解。
注解的字节码结构
class自身和class的成员都可以标注注解,这个类就是统一的在运行时获取被标注的注解。
说明 | |
---|---|
boolean isAnnotationPresent (Class<? extends Annotation> annotationClass) |
接受一个注解,运行时判断注解的类型是不是当前的注解。比如:TestInfo.class.getMethod(“born”).isAnnotationPresent(StudentInfo.class)判断born方法上的注解是不是StudentInfo.class注解 |
Annotation[] getAnnotations() | 获取所有的注解 |
2.1.1.2 Type
java中的type介绍
表示一个类的类型,一个类是泛型,基本类型,以及如何表示。
ParameterizedType
参数化类型,即泛型;例如:List、Map<K,V>等带有参数化的对象;
public interface ParameterizedType extends Type {
// 获取<>中的实际类型, 比如 List<T>的T
Type[] getActualTypeArguments();
// 获取<> 之前的类型,比如 List<T>的List
Type getRawType();
// 获取拥有者的类型 O<T>.I<S>,那么就返回 O<T>
Type getOwnerType();
}
TypeVariable
类型变量,即泛型中的变量;例如:T、K、V等变量,可以表示任何类;在这需要强调的是,TypeVariable代表着泛型中的变量,而ParameterizedType则代表整个泛型;
public interface TypeVariable<D extends GenericDeclaration> extends Type, AnnotatedElement{
// 一个形如TypeVariable<D extends GenericDeclaration> extends Type的泛型
// 返回上例中的 extends的右侧,没有就返回Object
Type[] getBounds();
// 返回泛型
D getGenericDeclaration();
// 返回名称 D
String getName();
// 返回注解的上界
AnnotatedType[] getAnnotatedBounds();
}
GenericArrayType
泛型数组类型,用来描述ParameterizedType、TypeVariable类型的数组;即List[] 、T[]等;
public interface GenericArrayType extends Type {
//返回数组的元素类型A<T>(A<T>[])或T(T[])
Type getGenericComponentType();
WildcardType
WildcardType是Type的子接口,用于描述形如“? extends classA” 或 “?super classB”的“泛型参数表达式”。
List<? extends String>
这种类型就叫WildcardType
public void hello( List<? extends String> o ){
}
```java
public interface WildcardType extends Type {
//获得泛型表达式的上界,上界 extends
Type[] getUpperBounds();
//获得泛型表达式的下限,下限 super
Type[] getLowerBounds();
}
2.1.1.3 AnnotatedType
和type类型对应,但是注解形式的
2.1.1.4 AccessibleObject
设置权限,Method等都继承了这个对象
比如将权限设置为可以获取
Method born = TestInfo.class.getMethod("born");
born.setAccessible(true);
setAccessible的实现
public void setAccessible(boolean flag) throws SecurityException {
SecurityManager sm = System.getSecurityManager();
// 检查是有权限设置sm.checkPermission(ACCESS_PERMISSION);
if (sm != null) sm.checkPermission(ACCESS_PERMISSION);
setAccessible0(this, flag);
}
2.1.1.5 Modifier 修饰符
比如一个方法定位为public static void hello
,那么根据
method_info {
u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count];
}
u2 access_flags
就是在字节码中放置修饰符的位置。
2byte的修饰符,每一位的含义都不同。比如 public static
的含义是—0x0001 |0x0008
即二进制末尾为 XXX1001
。
这个是method
的flag表
Flag Name | Value | Interpretation |
---|---|---|
ACC_PUBLIC | 0x0001 | Declared public; may be accessed from outside its package. |
ACC_PRIVATE | 0x0002 | Declared private; accessible only within the defining class. |
ACC_PROTECTED | 0x0004 | Declared protected; may be accessed within subclasses. |
ACC_STATIC | 0x0008 | Declared static. |
ACC_FINAL | 0x0010 | Declared final; must not be overridden (§5.4.5). |
ACC_SYNCHRONIZED | 0x0020 | 同步方法Declared synchronized; invocation is wrapped by a monitor use. |
ACC_BRIDGE | 0x0040 | A bridge method, generated by the compiler. |
ACC_VARARGS | 0x0080 | Declared with variable number of arguments. |
ACC_NATIVE | 0x0100 | Declared native; implemented in a language other than Java. |
ACC_ABSTRACT | 0x0400 | Declared abstract; no implementation is provided. |
ACC_STRICT | 0x0800 | Declared strictfp; floating-point mode is FP-strict. |
ACC_SYNTHETIC | 0x1000 | 是否是jvm合成的方法,Declared synthetic; not present in the source code. |
Modifier 就是代表了修饰符,本质是一个 代表了修饰符的 int 和额外的工具方法。比如判断是否是public
// mod是目标类的修饰符,和0X0001 做&预算
public static boolean isPublic(int mod) {
return (mod & PUBLIC) != 0;
}
内部的所有方法
2.1.2. Member 成员
具备三个子类Field,Method, Constructor
源码
public
interface Member {
/**标识所有的公共成员,包含父类
*/
public static final int PUBLIC = 0;
/** 是否是声明过的类
*/
public static final int DECLARED = 1;
/**获取对象所所属的类型
*/
public Class<?> getDeclaringClass();
/**成员的名称
*/
public String getName();
/**返回修饰符
*/
public int getModifiers();
/**是否是合成类
*/
public boolean isSynthetic(