这是我参与11月更文挑战的第1天,活动详情查看:2021最后一次更文挑战
AnnotatedElement接口是java.lang.reflect包中的一,通过这个接口可以延伸到整个反射包。AnnotatedElement表示目前正在此 VM 中运行的程序的一个已注释元素,相关子类结构如下:
- AnnotatedElement
- GenericDeclaration (java.lang.reflect)
- Executable (java.lang.reflect)
- Method (java.lang.reflect)
- Constructor (java.lang.reflect)
- Class (java.lang)
- Executable (java.lang.reflect)
- AccessibleObject (java.lang.reflect)
- Executable (java.lang.reflect)
- Method (java.lang.reflect)
- Constructor (java.lang.reflect)
- Field (java.lang.reflect)
- Executable (java.lang.reflect)
- Package (java.lang)
- Parameter (java.lang.reflect)
- TypeVariable (java.lang.reflect)
- TypeVariableImpl (sun.reflect.generics.reflectiveObjects)
- AnnotatedType (java.lang.reflect):子接口在AnnotatedTypeFactory工厂中生成实现类
- AnnotatedParameterizedType (java.lang.reflect)
- AnnotatedTypeVariable (java.lang.reflect)
- AnnotatedArrayType (java.lang.reflect)
- AnnotatedWildcardType (java.lang.reflect)
- AnnotatedTypeBaseImpl in AnnotatedTypeFactory (sun.reflect.annotation)
- Class (java.lang)
- GenericDeclaration (java.lang.reflect)
我从AnnotatedElement开始了解reflect包里的玄机。
一、java.lang.reflect.AnnotatedElement
1. AnnotatedElement
AnnotatedElement 接口用于表示VM 中被注解的元素;该接口可以用反射读取注释,但是返回的所有注释都是不可变和可序列化的。另外,该接口的方法返回的数组可以被调用者修改,而不会影响返回给其他调用者的数组,即数组读取后是各自独立的。
相关术语
- 直接声明(directly present):被注解元素上的单个注解
- 间接声明(indirectly present):被注解元素上的
重复注解- 重复注解:指类上存在的多个同类型注解
- 声明(present):被注解元素及其父类的
直接声明合集 - 关联(associated):子类及父类所有的注解
AnnotatedElement 接口包含以下几个方法:
- getAnnotation:从元素中获取
指定注解(包括继承的注解);否则返回null - getAnnotations:返回此元素上存在的所有注解(包括继承与重复的);否则返回null
- getDeclaredAnnotation:从元素中获取
指定注解(不包括继承的注解);否则返回null - getDeclaredAnnotations:从元素中获取所有的注解(包括重复注解,不包括继承的);否则返回null
- getAnnotationsByType 与 getDeclaredAnnotationsByType: 支持同一元素上存在多个相同类型的注解(repeatable annotation);如果任一方法的参数是可重复的注解类型,则可通过容器类(Map)查看重复注解
- isAnnotationPresent:校验注解是否存在指定注解
相关源码:
public interface AnnotatedElement {
/**
* 如果此元素上存在指定注解 annotationClass,返回注解类型T;否则为 null
*/
<T extends Annotation> T getAnnotation(Class<T> annotationClass);
/**
* 返回元素中存在的所有注解; 如果没有存在任何注解,返回值是长度为0。
* 该方法的调用者可以随意修改返回的数组,而不会影响返回给其他调用者的数组。
*/
Annotation[] getAnnotations();
/**
* 返回此元素关联的注解,如果不存在则返回长度为0的数组
* 该方法会检测参数是否为可重复的注解类型; 该方法的调用者可以自由修改返回的数组; 它不会影响返回给其他调用者的数组
*/
default <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass) {
T[] result = getDeclaredAnnotationsByType(annotationClass);
// 判断当前类是否有注解
if (result.length == 0 && // 当前类不存在直接或间接注解
this instanceof Class && // 当前元素表示一个类
AnnotationType.getInstance(annotationClass).isInherited()) { // 该注解可以继承
// 满足以上几个条件,就可以查询所表示元素父类的注解
Class<?> superClass = ((Class<?>) this).getSuperclass();
if (superClass != null) {
// 确定注解是否与超类相关联
result = superClass.getAnnotationsByType(annotationClass);
}
}
return result;
}
/**
* 如果存在直接注解,则返回该注解;否则返回 null。此方法忽略继承的注解。
*/
default <T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass) {
// 判断是否为空,为空抛出空指针异常
Objects.requireNonNull(annotationClass);
// 遍历所有直接存在的注释以寻找匹配的注解
for (Annotation annotation : getDeclaredAnnotations()) {
if (annotationClass.equals(annotation.annotationType())) {
// 在运行时进行动态转换比在编译时进行使代码更健壮
// Java.lang.Class类的cast()方法用于将指定的对象强制转换为此类的对象
return annotationClass.cast(annotation);
}
}
return null;
}
/**
* 获取所有注解。
*/
Annotation[] getDeclaredAnnotations();
/**
* 如果此类注解直接或间接存在,则返回此元素的指定类型的注解;此方法忽略继承的注解。 如果此元素上没有直接或间接指定的注解,则返回值为长度为 0 的数组。
* 此方法与getDeclaredAnnotation(Class)的区别在于该方法会检测其参数是否为可重复的注解类型,如果是会返回该类型的一个或多个注释
*/
default <T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass) {
Objects.requireNonNull(annotationClass);
return AnnotationSupport.
getDirectlyAndIndirectlyPresent(Arrays.stream(getDeclaredAnnotations()).
collect(Collectors.toMap(Annotation::annotationType,
Function.identity(),
((first,second) -> first),
LinkedHashMap::new)),
annotationClass);
}
/**
* 如果此元素上存在指定类型的注释,则返回 true,否则返回 false。 此方法主要是为了方便访问标记注释而设计的
*/
default boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
return getAnnotation(annotationClass) != null;
}
}
如上所示,源码中调用了AnnotationSupport的getDirectlyAndIndirectlyPresent方法获取当前类的直接注解;该类顾名思义是为注解提供支持的工具类。
2. AnnotationSupport
AnnotationSupport类 位于sun.reflect.annotation包中,而sun包与Java平台的标准无关,与操作系统相关,不同操作系统的sun包实现也不一样。Oracle不建议开发者使用该包中的代码,因为该包的类实现与操作系统相关且可能在新的版本中被去除。
相关源码如下:
public final class AnnotationSupport {
private static final JavaLangAccess LANG_ACCESS = sun.misc.SharedSecrets.getJavaLangAccess();
/**
* 查找并返回的所有匹配的annotations(直接+间接)
* 返回的数组元素顺序取决于提供的Map的迭代顺序.
* @param annotations 用于查询注解的Map
* @param 注解类
* @return annoClass的实例数组或空数组(如果没有找到)
*/
public static <A extends Annotation> A[] getDirectlyAndIndirectlyPresent(
Map<Class<? extends Annotation>, Annotation> annotations,
Class<A> annoClass) {
List<A> result = new ArrayList<A>();
// 获取直接注解
@SuppressWarnings("unchecked")
A direct = (A) annotations.get(annoClass);
if (direct != null)
result.add(direct);
// 获取间接注解
A[] indirect = getIndirectlyPresent(annotations, annoClass);
if (indirect != null && indirect.length != 0) {
boolean indirectFirst = direct == null ||
containerBeforeContainee(annotations, annoClass);
//添加所有间接注解
result.addAll((indirectFirst ? 0 : 1), Arrays.asList(indirect));
}
@SuppressWarnings("unchecked")
// 使用annoClass填充数组元素
A[] arr = (A[]) Array.newInstance(annoClass, result.size());
return result.toArray(arr);
}
/**
* 查找与给定annoClass相关的间接注解,并返回存在于annotations中的所有匹配项.
*
* @param 用于按类型索引搜索的注解
* @param 要搜索的注解类型
* @return annoClass的实例数组或空数组
*/
private static <A extends Annotation> A[] getIndirectlyPresent(
Map<Class<? extends Annotation>, Annotation> annotations,
Class<A> annoClass) {
//Repeatable 类是元注解,用于赋予注解重复特性
Repeatable repeatable = annoClass.getDeclaredAnnotation(Repeatable.class);
if (repeatable == null)
return null; // 表示没有间接注解
Class<? extends Annotation> containerClass = repeatable.value();
Annotation container = annotations.get(containerClass);
if (container == null)
return null; // 表示没有对应的注解容器
// Unpack container
A[] valueArray = getValueArray(container);
checkTypes(valueArray, container, annoClass);
return valueArray;
}
/**
* 确定在给定映射的KEY中,conatiner 类是否在 containeree 类之前
* @return 迭代 annotations.keySet() 时在容器类之前找到容器类,则为 true
*/
private static <A extends Annotation> boolean containerBeforeContainee(
Map<Class<? extends Annotation>, Annotation> annotations,
Class<A> annoClass) {
// 获取注解类的直接注解(可重复的)
Class<? extends Annotation> containerClass =
annoClass.getDeclaredAnnotation(Repeatable.class).value();
for (Class<? extends Annotation> c : annotations.keySet()) {
if (c == containerClass) return true;
if (c == annoClass) return false;
}
// Neither containee nor container present
return false;
}
/**
* 查找并返回匹配给定类的所有相关注释.
*
* 返回的数组中元素的顺序取决于迭代MAP的顺序.
*
* @param declaredAnnotations 声明的注解
* @param decl the 用于搜索注解的class
* @param annoClass 搜索的注解类型
*
* @return 返回注解数组或空数组.
*/
public static <A extends Annotation> A[] getAssociatedAnnotations(
Map<Class<? extends Annotation>, Annotation> declaredAnnotations,
Class<?> decl,
Class<A> annoClass) {
Objects.requireNonNull(decl);
// 获取直接或间接注解
A[] result = getDirectlyAndIndirectlyPresent(declaredAnnotations, annoClass);
// Search inherited
if(AnnotationType.getInstance(annoClass).isInherited()) {
Class<?> superDecl = decl.getSuperclass();
while (result.length == 0 && superDecl != null) {
result = getDirectlyAndIndirectlyPresent(LANG_ACCESS.getDeclaredAnnotationMap(superDecl), annoClass);
superDecl = superDecl.getSuperclass();
}
}
return result;
}
/* Reflectively invoke the values-method of the given annotation
* (container), cast it to an array of annotations and return the result.
*/
private static <A extends Annotation> A[] getValueArray(Annotation container) {
try {
// According to JLS the container must have an array-valued value
// method. Get the AnnotationType, get the "value" method and invoke
// it to get the content.
Class<? extends Annotation> containerClass = container.annotationType();
AnnotationType annoType = AnnotationType.getInstance(containerClass);
if (annoType == null)
throw invalidContainerException(container, null);
Method m = annoType.members().get("value");
if (m == null)
throw invalidContainerException(container, null);
m.setAccessible(true);
// This will erase to (Annotation[]) but we do a runtime cast on the
// return-value in the method that call this method.
@SuppressWarnings("unchecked")
A[] values = (A[]) m.invoke(container);
return values;
} catch (IllegalAccessException | // couldn't loosen security
IllegalArgumentException | // parameters doesn't match
InvocationTargetException | // the value method threw an exception
ClassCastException e) {
throw invalidContainerException(container, e);
}
}
// 表示注解格式错误
private static AnnotationFormatError invalidContainerException(Annotation anno,
Throwable cause) {
return new AnnotationFormatError(
anno + " is an invalid container for repeating annotations",
cause);
}
/* 检查注解数组annotations 中所有元素是否是annoClass类型
*/
private static <A extends Annotation> void checkTypes(A[] annotations,
Annotation container,
Class<A> annoClass) {
for (A a : annotations) {
if (!annoClass.isInstance(a)) {
throw new AnnotationFormatError(
String.format("%s is an invalid container for " +
"repeating annotations of type: %s",
container, annoClass));
}
}
}
}
二、GenericDeclaration 及其实现类
GenericDeclaration接口与泛型相关,只有实现了该接口的类才可以使用泛型<E>。
1. GenericDeclaration
GenericDeclaration 接口与泛型相关,声明了类型变量中所有实体的通用接口;而类型变量指的是 Class,Constructor,Method等类。相关类结构如下:
- AnnotatedElement
- GenericDeclaration (java.lang.reflect)
- Executable (java.lang.reflect)
- Method (java.lang.reflect)
- Constructor (java.lang.reflect)
- Class (java.lang)
- Executable (java.lang.reflect)
- GenericDeclaration (java.lang.reflect)
GenericDeclaration接口只有一个方法声明 public TypeVariable<?>[] getTypeParameters(),用于按声明顺序返回一个TypeVariable对象数组,返回的其实是类上定义的泛型。
例如
public class Test<T> {
public static void main(String[] args) {
TypeVariable<Class<Test>>[] typeParameters = Test.class.getTypeParameters();
for (TypeVariable typeVariable: typeParameters) {
System.out.println(typeVariable.getName());
}
}
}
在DEBUG时,可以看到getTypeParameters返回的数组包含一个名为T的元素,这个其实是在类Test中提取的泛型声明。
2. AccessibleObject
AccessibleObject 类用于可访问性控制,是 Field、Method 和 Constructor 对象的基类。默认情况下,Java 语言会对代码的访问进行控制检查,而设置标记可以在使用时抑制检查。
当字段、方法或构造函数用于设置或获取字段、调用方法或创建和初始化类的新实例时,将执行访问检查——public、default(包)、protected和private,
在反射对象中设置accessible标志允许具有足够权限的复杂应用程序(如 Java 对象序列化或其他持久性机制)使用通常情况下被禁止的方式操作对象(默认情况下,反射对象不可访问)。
相关字段:
// Permission 对象,用于检查客户端是否有足够的权限来阻止 Java 语言访问控制检查。
static final private java.security.Permission ACCESS_PERMISSION =
new ReflectPermission("suppressAccessChecks");
// 指示此对象是否覆盖语言级别的访问检查
boolean override;
// 子类用于创建字段、方法和构造函数访问器的反射工厂
static final ReflectionFactory reflectionFactory =
AccessController.doPrivileged(
new sun.reflect.ReflectionFactory.GetReflectionFactoryAction());
// 用于共享访问检查逻辑,记录最近一次的成功记录,加速校验
volatile Object securityCheckCache;
相关方法:
- 与注解相关,带getDeclaredXXX用于获取直接注解;这几个方法是实现了
AnnotatedElement接口中的方法- getAnnotation
- getAnnotations
- getAnnotationsByType
- getDeclaredAnnotation
- getDeclaredAnnotations
- getDeclaredAnnotationsByType
- isAnnotationPresent:查看是否存在指定类型的注解
- 与访问权限相关
- isAccessible:获取此对象的accessible标志的值,表示是否有权限访问
- setAccessible、setAccessible、setAccessible0 用于允许访问
- checkAccess 用于检测反射时调用者是否有权限调用方法,当检测不通过时调用
slowCheckMemberAccess方法 - slowCheckMemberAccess
相关实例:
public class Test<T> {
@Deprecated
private String msg = "msg";
public static void main(String[] args) throws NoSuchFieldException {
// 获取非public的字段
for (Field field: Test.class.getDeclaredFields()) {
System.out.println(field.getGenericType().getTypeName());
System.out.println(field.isAccessible());
System.out.println(field.isAnnotationPresent(Deprecated.class));
System.out.println(field);
}
}
}
setAccessible
存在三个设置访问权限的方法,以其中一个源码为例:
public static void setAccessible(AccessibleObject[] array, boolean flag)
throws SecurityException {
SecurityManager sm = System.getSecurityManager();
if (sm != null) sm.checkPermission(ACCESS_PERMISSION);
for (int i = 0; i < array.length; i++) {
setAccessible0(array[i], flag);
}
}
- 首先,会先从System获取
SecurityManager(安全管理器),通过这个类判断客户端是否有足够的权限阻止检查; - 检验成功时,调用setAccessible0方法设置标志;
- 校验失败,则抛出异常
AccessControlException.
checkAccess
checkAccess方法的判断逻辑:
- 若调用者和被调用者的类一致,那么验证通过;
- 如果以下三个条件成立,则判断
securityCheckCache中是否存在[caller,targetClass]的缓存或是caller==cache,存在则验证通过- 调用的是set方法(obj不为空)
- 字段、函数、构造器是受保护的
- set方法设置的类型不是目被调用者
- 否则,调用
slowCheckMemberAccess方法进入缓慢校验的路径。
void checkAccess(Class<?> caller, Class<?> clazz, Object obj, int modifiers)
throws IllegalAccessException
{
if (caller == clazz) { // quick check
return; // ACCESS IS OK
}
Object cache = securityCheckCache; // read volatile
Class<?> targetClass = clazz;
if (obj != null
&& Modifier.isProtected(modifiers)
&& ((targetClass = obj.getClass()) != clazz)) {
// Must match a 2-list of { caller, targetClass }.
if (cache instanceof Class[]) {
Class<?>[] cache2 = (Class<?>[]) cache;
if (cache2[1] == targetClass &&
cache2[0] == caller) {
return; // ACCESS IS OK
}
// (Test cache[1] first since range check for [1]
// subsumes range check for [0].)
}
} else if (cache == caller) {
// Non-protected case (or obj.class == this.clazz).
return; // ACCESS IS OK
}
// If no return, fall through to the slow path.
slowCheckMemberAccess(caller, clazz, obj, modifiers, targetClass);
}
slowCheckMemberAccess
slowCheckMemberAccess方法通过缓慢遍历校验是否拥有调用权限,由以下源码可知该方法执行时会调用ensureMemberAccess方法进行权限判定,判定失败抛出异常IllegalAccessException,表示非法的访问异常;判定成功则更新缓存,便于下次快速校验。
void slowCheckMemberAccess(Class<?> caller, Class<?> clazz, Object obj, int modifiers,
Class<?> targetClass)
throws IllegalAccessException
{
Reflection.ensureMemberAccess(caller, clazz, obj, modifiers);
// 成功则更新缓存
Object cache = ((targetClass == clazz)
? caller
: new Class<?>[] { caller, targetClass });
// 缓存,加快下次校验
securityCheckCache = cache; // 写入 volatile变量
}
public static void ensureMemberAccess(Class<?> var0, Class<?> var1, Object var2, int var3) throws IllegalAccessException {
if (var0 != null && var1 != null) {
if (!verifyMemberAccess(var0, var1, var2, var3)) {
throw new IllegalAccessException("Class " + var0.getName() + " can not access a member of class " + var1.getName() + " with modifiers "" + Modifier.toString(var3) + """);
}
} else {
throw new InternalError();
}
}