反射随笔:反射包的结构

Posted lx-lixiao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了反射随笔:反射包的结构相关的知识,希望对你有一定的参考价值。

反射随笔(一):反射包的结构

前言:

? 源码学习基于JDK 8

一,Interface

1,结构

- java.lang.reflect.AnnotatedElement
    - java.lang.reflect.AnnotatedType
        * java.lang.reflect.AnnotatedArrayType
        * java.lang.reflect.AnnotatedParameterizedType
        * java.lang.reflect.AnnotatedTypeVariable
        * java.lang.reflect.AnnotatedWildcardType
    - java.lang.reflect.GenericArrayType    
    - java.lang.reflect.GenericDeclaration
    - java.lang.reflect.TypeVariable
- java.lang.reflect.InvocationHandler
- java.lang.reflect.Member
- java.lang.reflect.Type
    - java.lang.reflect.ParameterizedType
    - java.lang.reflect.WildcardType

2,分类简介

2.1,java.lang.reflect.AnnotatedElement

? AnnotatedElement该接口代表了一个在JVM内运行的一个被注解标注的元素,可以是Class,Method,Field,Constructor,Package等,通俗来讲就好比如果你买了商品那你就是顾客,买商品就是被注解标注,顾客就好比这个类,通过这个接口的方法你就可以获取某个Method,Field,Constructor,Package等 上面的注解信息,前提是这些元素都实现了这个接口。

该接口内的方法相对来说比较常见,所以不一一介绍,只区分一下getAnnotation()和getDeclaredAnnotation()的区别,这两个方法,不同的类调用,返回结果是不同的,但是比较好总结的。对于类Class和Package来说是一样的(Package调用的就是Class的方法):

? getAnnotation() 返回该元素上的所有注解,包括从父类继承下来的(当然被继承下来的注解必须是被@Inherited元注解标记的)

? getDeclaredAnnotation() 返回该元素上的所有注解,不包括从父类继承下来的

而对于Method、Field、Constructor、Parameter来说,这两个方法返回值都是一样的,返回的都是该元素上的所有注解。

2.2,AnnotatedType、AnnotatedParameterizedType、AnnotatedTypeVariable、AnnotatedWildcardType

? 其中AnnotatedType为其他的几个的父接口,就一个方法getType() ,主要是用来获取元素上注解的类型,最明显的一个操作如下:

public class Test implements @Annotation Interface {
}
//通过AnnotatedType a = Test.class.getAnnotatedSuperclass()
//通过这个a就可以获取@Annotation这个注解

其他接口暂时不研究(个人研究的有点模糊,有弄清楚同学可以留言分享分享)

2.3,GenericArrayType

? 获取泛型数组类型,比如 List[] ,T[] 。接口中只有一个方法getGenericComponentType(), 该方法返回的就是泛型数组中泛型的类型,比如T[] 中的T,当数组是一个多维数组时,该方法只会去除最右边那一层,比如 List[] [] ,调用getGenericComponentType方法后返回的是List[]。

2.4,GenericDeclaration

? 泛型声明,实现该接口的类才可以声明泛型,而目前为止,它的子类只有三个Class、Constructor、Method。需要说的是声明泛型和使用泛型不是一回事,如图:
技术图片

结果应该是挺明显的,Field上可以使用泛型,但是它却不可以主动声明泛型,如果当前类没有泛型,那么Field不可以使用泛型,但是Method和Constructor就不同,它们在类上没有泛型的情况下依然可以声明泛型。该接口只有一个方法getTypeParameters,该方法便是用来获取泛型的类型,如上图Test12 的E。

2.5,InvocationHandler

? 这个接口不介绍,JDK代理必须要使用的一个接口,基本上大家都见过

2.5,Member

? 用来记录反射对象的一些标记信息

//标记用来只获取公开的信息(只被public修饰的,包括从超类继承的)
public static final int PUBLIC = 0;
//标记用来获取所有的信息(不包括继承的),无视修饰符
public static final int DECLARED = 1;
//获取申明类
public Class<?> getDeclaringClass();
//获取名称,比如 int a = 1;中的a  public void test();中的test
public String getName();
//获取修饰符 比如 public、 static、final 等
public int getModifiers();
//是否人工合成的
public boolean isSynthetic();
2.6,ParameterizedType

? 参数化类型,也就是泛型,内部方法如下:

// 获取实际类型参数,例如:
// public Test extends Test1<String>{}  中的String
Type[] getActualTypeArguments();
// 获取声明泛型的对象类型 如:Test<T> 中的Test
Type getRawType();
// 获取所有者类型,如果有内部类时,内部类上有泛型,调用这个方法返回的便是内部类外面的那个类
Type getOwnerType();
2.7,Type

? Java语言中,所有类型的父接口

2.8,TypeVariable

? 类型变量,指的就是泛型中的类型,如Test 中的T,方法如下:

//获得该类型变量的上限,也就是泛型中extend右边的值,如 List<T extends Test> 中的Test,因为泛型可以是多个,所以返回值是数组,如果没有extends,则默认是Object
Type[] getBounds();
//获得该类型变量的声明实体,如:List<T extends Test> 中的List
D getGenericDeclaration();
//获得类型变量的名称,如:List<T extends Test> 中的T
String getName();
//该方法暂时没搞清
AnnotatedType[] getAnnotatedBounds();
2.8,WildcardType

? 通配符类型,如: ? extends classA、?super classB。方法如下:

//获取泛型表达式的上界  ? extends ClassA 中的ClassA
Type[] getUpperBounds();
//获取泛型表达式的下界  ? super ClassB 中的ClassB
Type[] getLowerBounds();

二、Class

1,结构

- java.lang.reflect.AccessibleObject
    - java.lang.reflect.Executable
        - java.lang.reflect.Constructor
    - java.lang.reflect.Field
- java.lang.reflect.Array   
- java.lang.reflect.Modifier
- java.lang.reflect.Parameter
- java.lang.reflect.Proxy
- java.lang.reflect.ReflectAccess
- java.lang.reflect.ReflectPermission
java.lang.reflect.WeakCache

2,分类简介

2.1,AccessibleObject

? 先看官方解释:AccessibleObject类是字段、方法和构造函数对象的基类。它提供了在使用反射对象时将其标记为禁止默认Java语言访问控制检查的能力。当字段、方法或构造函数分别用于设置或获取字段、调用方法或创建和初始化类的新实例时,将执行访问检查(针对public、default (package)访问、protected和private成员)。

在反射对象中设置可访问标志允许具有足够特权的复杂应用程序(如Java对象序列化或其他持久性机制)以通常禁止的方式操作对象。

默认情况下,反射对象是不可访问的。

个人感觉,这个类就是设置要不要绕过jvm控制检查的,核心方法setAccessible,当我们要对反射拿到的方法进行执行或者对通过反射拿到的字段进行赋值等操作时,需要设置setAccessible为 true来绕开Java语言的控制检查能力。网上有人说是作用于权限修饰符的,比如访问private需要设置,访问public就不许要,其实这么理解是不对的,Java语言的控制检查不仅仅是对访问修饰符做检查,还会对是不是final等做检查,比如我们都知道用final修饰的变量是不可以被修饰的,如果通过反射对public final 修饰的变量赋值时同样会报错,如下图技术图片

,所以设置setAccessible(true),不仅仅是绕过访问规则,也绕过了Java语言的某种其他规则,比如被final修饰的不可变规则。

2.2 Array

? 这个类项目中一般很少用到,主要是通过这个类,调用native构建数组,这里不多分享,有兴趣的可以自己玩玩

2.3,Constructor,Field,Method,Parameter

? 这几个类大家很常用,这里也不多分享,后面详解

2.4,Executable

? 这个类是Method和Constructor公共方法抽取的共享类

2.5,Modifier

? Java语言中的所有的修饰词,采用不同的int值表示不同的修饰字,不详解

2.6,ReflectAccess和ReflectPermission

? 这两个都是反射权限相关的类,也不多分享

2.7,WeakCache

? 反射过程中的一个弱缓存,没啥特殊功能

以上是关于反射随笔:反射包的结构的主要内容,如果未能解决你的问题,请参考以下文章

随笔12 java反射机制

反射,动态代理随笔

反射,动态代理随笔

反射,动态代理随笔

反射,动态代理随笔

java反射学习个人随笔