文章目录
前言
时间多少不是努力的标准,而是你是否纠正了错误,提高了水平。没有进步,那只是单纯的浪费时间,别感动了自己
java的反射还是得会一点的
一、什么是反射?
Oracle 官方对反射的解释是:
Reflection enables Java code to discover information about the fields, methods and constructors of loaded classes, and to usereflected fields, methods, and constructors to operate on their underlying counterparts, within security restrictions. The API accommodates applications that need access to either the public members of a target object (based on its runtime class) or the members declared by a given class. It also allows programs to suppress default reflective access control.
总结就是:通过反射,我们可以在运行时获得程序或程序集中每一个类型的成员和成员的信息
二、反射的API 规范
下图来自于oracle官网
CLass类并不在这里,它属于java.lang包,不属于java.lang.reflect.
三、反射API使用示例
AnnotatedElement
Represents an annotated element of the program currently running in this VM.
即表示带注解的元素
这是一个接口,Class、Constructor、Field、Method、Parameter自然是实现了该接口,此外还有Package、TypeVariable。
// 是否被入参的注解标注
boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
// 获取注解对象
<T extends Annotation> T getAnnotation(Class<T> annotationClass);
// 获取该元素上的所有注解
Annotation[] getAnnotations();
// 返回与此元素关联的注释.此方法与getAnnotation()的区别在于,此方法检测其参数是否为可重复注解类型
<T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass)
// 如果直接存在这样的注解(是直接),则返回此元素对指定类型的注释,否则返回 null
<T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass)
// 如果直接存在这样的注解(是直接),则返回此元素对指定类型的注解,否则返回 null,此方法检测其参数是否为可重复注解类型
<T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass)
//获取所有直接标注在该元素上的注解
Annotation[] getDeclaredAnnotations()
下面是例子
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface Name {
String value();
}
@Name("parent")
class TestParent{
}
public class Test extends TestParent {
public static void main(String[] args) {
Class<Test> testClass = Test.class;
System.out.println(testClass.isAnnotationPresent(Name.class)); // true
System.out.println(testClass.getAnnotation(Name.class)); //@Name(value=parent)
System.out.println(Arrays.toString(testClass.getAnnotations())); // [@Name(value=parent)]
System.out.println(Arrays.toString(testClass.getAnnotationsByType(Name.class))); // [@Name(value=parent)]
System.out.println(testClass.getDeclaredAnnotation(Name.class)); // null
System.out.println(Arrays.toString(testClass.getDeclaredAnnotationsByType(Name.class))); // []
System.out.println(Arrays.toString(testClass.getDeclaredAnnotations())); //[]
}
}
Type
Type 是 Java 编程语言中所有类型的父接口,GenericArrayType、ParameterizedType、TypeVariable、WildcardType是它的子接口,当然Class类也实现了它。
它只有一个方法
// 返回描述此类型的字符串,包括有关任何类型参数的信息。
String getTypeName()
Member
成员是表示单个成员(字段或方法)或构造函数的标识信息的接口。其实现主要有3个,Field、Method、Constructor
// 获取当前成员是在哪个Class中声明的
Class<?> getDeclaringClass();
// 获取成员名称
String getName();
// 获取成员的访问标识(public,private...)
int getModifiers();
// 如果该成员是由编译器引入的,则返回true
boolean isSynthetic()
使用示例
interface SuperClass<T> {
T method(T param);
}
public class Test implements SuperClass<String> {
@Override
public String method(String param) {
return "hello";
}
public static void main(String[] args) throws Exception{
Class<Test> clazz = Test.class;
Method[] methods = clazz.getDeclaredMethods();
System.out.println(methods.length); // 3
Method method = clazz.getMethod("method", Object.class);
System.out.println(method.getDeclaringClass()); // class Test
System.out.println(Modifier.isPublic(method.getModifiers())); // true
System.out.println(method.isSynthetic()); // true
}
}
使用javap命令查看Test类的成员,可以看到相比源代码,多出了一个方法,这是由编译器生成的。(兼容低版本)
GenericDeclaration
声明类型变量的所有实体的通用接口,继承自AnnotatedElement,说明它有获取注解信息的能力
public interface GenericDeclaration extends AnnotatedElement {
// 获取类型变量
public TypeVariable<?>[] getTypeParameters();
}
它只有四个实现,也只有这四个实现可以获取类型参数
ParameterizedType、GenericArrayType、TypeVariable、WildcardType以及Class
这5个Type子接口或者实现构成了java语言层面的类型。
ParameterizedType
ParameterizedType表示参数化类型
// 获取实际类型参数
Type[] getActualTypeArguments();
// 获取声明此类型的类或接口的Type对象。
Type getRawType();
// 获取该类型所属的类型
Type getOwnerType();
看注释应该是一脸懵逼的,还是看例子吧。
public class Test {
public static <U> void method(Map.Entry<String,U> mapEntry){
}
public static void main(String[] args) throws Exception{
Method method = Test.class.getDeclaredMethod("method",Map.Entry.class);
Type genericType = method.getGenericParameterTypes()[0];
System.out.println(genericType instanceof ParameterizedType); // true
ParameterizedType parameterizedType = (ParameterizedType) genericType;
System.out.println(parameterizedType.getRawType()); // interface java.util.Map$Entry
System.out.println(Arrays.toString(parameterizedType.getActualTypeArguments())); // [class java.lang.String, U]
System.out.println(parameterizedType.getOwnerType()); // interface java.util.Map
}
}
GenericArrayType
GenericArrayType表示泛型数组类型
public interface GenericArrayType extends Type {
// 获取数组元素类型
Type getGenericComponentType();
}
例子
public class Test<T> {
private T[] objs;
public static void main(String[] args) throws Exception{
Field objs = Test.class.getDeclaredField("objs");
System.out.println(objs.getType()); // class [Ljava.lang.Object;
Type genericType = objs.getGenericType();
System.out.println(genericType instanceof GenericArrayType); //true
GenericArrayType genericArrayType = (GenericArrayType) genericType;
System.out.println(genericArrayType.getGenericComponentType().getClass()); // class sun.reflect.generics.reflectiveObjects.TypeVariableImpl
System.out.println(genericArrayType.getGenericComponentType().getTypeName()); // T
}
}
TypeVariable
它继承了AnnotatedElement,表明了它可以被注解标注
public interface TypeVariable<D extends GenericDeclaration> extends Type, AnnotatedElement {
// 获取表示此类型变量上限的Type对象数组
Type[] getBounds();
// 获取泛型声明者(不太会形容,下面有例子)
D getGenericDeclaration();
// 获取名字(泛型变量都有名字,如Map的KV)
String getName();
// 获取表示此类型变量上限的AnnotatedType对象数组
AnnotatedType[] getAnnotatedBounds();
}
例子
public class Test<@Test.Anno("TYPE_PARAMETER") T extends @Test.Anno("TYPE_USE") CharSequence & Closeable > {
@Target({ElementType.TYPE_PARAMETER,ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@interface Anno{
String value();
}
public static void main(String[] args) throws Exception{
TypeVariable<Class<Test>>[] typeParameters = Test.class.getTypeParameters();
System.out.println(typeParameters.length); // 1
TypeVariable<Class<Test>> typeParameter = typeParameters[0];
System.out.println(typeParameter.getGenericDeclaration()); // class Test
for (Annotation annotation : typeParameter.getAnnotations()) {
System.out.println(annotation); // @Test$Anno(value=TYPE_PARAMETER)
}
Type[] bounds = typeParameter.getBounds();
System.out.println(Arrays.toString(bounds)); // [interface java.lang.CharSequence, interface java.io.Closeable]
AnnotatedType[] annotatedBounds = typeParameter.getAnnotatedBounds();
for (AnnotatedType annotatedBound : annotatedBounds) {
for (Annotation annotation : annotatedBound.getAnnotations()) {
System.out.println(annotation); // @Test$Anno(value=TYPE_USE)
}
}
}
}
WildcardType
WildcardType 表示通配符类型表达式
源码
public interface WildcardType extends Type {
// 获取上界
Type[] getUpperBounds();
// 获取下界
Type[] getLowerBounds();
}
例子
public class Test {
public void test(List<? extends CharSequence> a, Comparator<? super Cloneable> comparator){}
public static void main(String[] args) throws Exception{
Method method = Test.class.getMethod("test",List.class,Comparator.class);
Type[] genericParameterTypes = method.getGenericParameterTypes();
for (Type genericParameterType : genericParameterTypes) {
ParameterizedType parameterizedType = (ParameterizedType) genericParameterType;
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println(actualTypeArgument instanceof WildcardType); //true true
assert actualTypeArgument instanceof WildcardType;
WildcardType type = (WildcardType) actualTypeArgument;
System.out.println(Arrays.toString(type.getLowerBounds())); // [] [interface java.lang.Cloneable]
System.out.println(Arrays.toString(type.getUpperBounds())); // [interface java.lang.CharSequence] [class java.lang.Object]
System.out.println(type); // ? extends java.lang.CharSequence ? super java.lang.Cloneable
}
}
}
}
AnnotatedParameterizedType
AnnotatedParameterizedType表示参数化类型的潜在注释使用,其类型参数本身可能表示类型的注释使用
public interface AnnotatedParameterizedType extends AnnotatedType {
// 返回此参数化类型的潜在注释实际类型参数
AnnotatedType[] getAnnotatedActualTypeArguments();
}
public class Test extends @Ann("map") HashMap<@Ann("str") String, @Ann("obj") Object> {
public static void main(String[] args) throws Exception {
AnnotatedType annotatedSuperclass = Test.class.getAnnotatedSuperclass();
AnnotatedParameterizedType type = (AnnotatedParameterizedType) annotatedSuperclass;
System.out.println(type.getType()); // java.util.HashMap<java.lang.String, java.lang.Object>
System.out.println(type.getAnnotation(Ann.class)); // @Ann(value=map)
AnnotatedType[] annotatedActualTypeArguments = type.getAnnotatedActualTypeArguments();
for (AnnotatedType annotatedActualTypeArgument : annotatedActualTypeArguments) {
System.out.println(annotatedActualTypeArgument.getType()); // class java.lang.String class java.lang.Object
System.out.println(annotatedActualTypeArgument.getAnnotation(Ann.class)); // @Ann(value=str) @Ann(value=obj)
}
}
}
总结
这篇博客对反射相关的API做了比较详细的介绍,反射的使用在框架中到处都是,我们没有理由不学习。