Java从入门到精通_学习笔记17(反射)
Class类与Java反射
通过Java反射机制,可以在程序中访问已经装载到JVM中的Java对象的描述,实现访问、检测和修改描述Java对象本身信息的功能。Java反射机制的功能十分强大,在java.lang.reflect包中提供了对该功能的支持。
所有Java类均继承了Object类,在Object类中定义了一个getClass()方法,该方法返回一个类型为Class的对象。利用Class类的对象,可以访问getClass()方法返回的该对象的描述信息。
注:
- 在通过getFields()和getMethods()方法依次获得权限为public的成员变量和方法时,将包含从超类中继承到的成员变量和方法;而通过方法getDeclaredFields()和getDeclaredMethods()只是获得在本类中定义的所有成员变量和方法。
1. 访问构造方法
通过下列一组方法访问类的构造方法:
- getConstructors()
- getConstructor(Class<?>…parameterTypes)
- getDeclaredConstructors()
- getDeclaredConstructor(Class<?>…parameterTypes)
注:每个Constructor对象代表一个构造方法,利用Constructor对象可以操纵相应的构造方法。
如果是访问指定的构造方法,需要根据该构造方法的入口参数的类型来访问。例如,访问一个入口参数类型依次为String和int型的构造方法,通过下面两种方式均可实现。
objectClass.getDeclaredConstructor(String.class , int.class); objectClass.getDeclaredConstructor(new Class[]{String.class , int.class});
通过java.lang.reflect.Modifier类可以解析出getModifiers()方法的返回值所表示的修饰符信息,在该类中提供了一系列用来解析的静态方法,既可以查看是否被指定的修饰符修饰,还可以以字符串的形式获得所有修饰符。
2. 访问成员变量
在通过下列一组方法访问成员变量:
- getFields()
- getField(String name)
- getDeclaredFields()
- getDeclaredField(String name)
注:每个Field对象代表一个成员变量,利用Field对象可以操纵相应的成员变量。
**如果是访问指定的成员变量,可以通过该成员变量的名称来访问。**例如,访问一个名称为birthday的成员变量,访问方法如下:
object.getDeclaredField("birthday");
3. 访问方法
通过下列一组方法访问方法:
- getMethods()
- getMethod(String name, Class<?>…parameterTypes)
- getDeclaredMethods()
- getDeclaredMethod(String name, Class<?>…parameterTypes)
注:每个Method对象代表一个方法,利用Method对象可以操纵相应的方法。
如果是访问指定的方法,需要根据该方法的名称和入口参数的类型来访问。 例如,访问一个名称为print、入口参数类型依次为String和int型的方法,通过下面两种方式均可实现:
- objectClass.getDeclaredMethod(“print”, String.class, int.class);
- objectClass.getDeclaredMethod(“print”, new Class[ ] {String.class, int.class });
使用Annotation功能
Java中提供了Annotation功能,该功能可用于类、构造方法、成员变量、方法、参数等的声明中。该功能并不影响程序的运行,但是会对编译器警告等辅助工具产生影响。
1. 定义Annotation类型
在定义Annotation类型时,也需要用到用来定义接口的interface关键字,但需要在interface关键字前加一个“@”符号,即定义Annotation类型的关键字为@interface,这个关键字的隐含意思是继承了java.lang.annotation.Annotation接口。
代码演示:
// 无任何成员 public @interface NoMemberAnnotation{ }
// 包含多个成员 public @interface NoMemberAnnotation{ String describe(); Class type(); }
// 为成员设置默认值 public @interface NoMemberAnnotation{ String describe() default"<默认值>"; Class type() default void.class; }
通过Annotation类型@Target来设置Annotation类型适用的程序元素种类:
通过Annotation类型@Retention可以设置Annotation的有效范围:
2. 访问Annotation信息
- 如果在定义Annotation类型时将@Retention设置为RetentionPolicy.RUNTIME,那么在运行程序时通过反射就可以获取到相关的Annotation信息,如获取构造方法、字段和方法的Annotation信息。
- 类Constructor、Field和Method均继承了AccessibleObject类,在AccessibleObject中定义了3个关于Annotation的方法,其中方法isAnnotationPresent(Class<? extends Annotation> annotationClass)用来查看是否添加了指定类型的Annotation,如果是则返回true,否则返回false;方法getAnnotation(ClassannotationClass)用来获得指定类型的Annotation,如果存在则返回相应的对象,否则返回null;方法getAnnotations()用来获得所有的Annotation,该方法将返回一Annotation数组。
- 在类Constructor和Method中还定义了方法getParameterAnnotations(),
用来获得为所有参数添加的Annotation,将以Annotation类型的二维数组返回,在数组中的顺序与声明的顺序相同,如果没有参数则返回一个长度为0的数组;如果存在未添加Annotation的参数,将用一个长度为0的嵌套数组占位。