java 之 反射reflection源码分析

本文深入探讨Java反射机制,从源码和字节码的角度分析反射的使用。介绍了AnnotatedElement、Type、AccessibleObject、Modifier等辅助类,以及Field、Method、Constructor等成员类。此外,还讲解了类的组成、数组和枚举、静态代理和动态代理,并讨论了Class类及其在反射中的重要性。
摘要由CSDN通过智能技术生成

—> go to 总目录

初衷是对反射的使用和字节码了解后,产生了想探究更深层次的原理,这就绕不过对源码的分析。了解后,发现对源码的分析可以分为两块:

  • 源码和字节码的对应关系。
  • 运行时反射机制的调用。

想要更深刻理解,最好先了解字节码知识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(
  • 5
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值