Java 的反射与注解
反射
反射机制与 Class 类
反射机制是程序在运行的中途,动态地获取一个类或者对象的成员与方法,并使用它们的机制。反射是通过 java.lang.Class 类的方法来实现。
Java 中每个对象都是 Class 类的一个对象,可以通过下面方式获取到 Class 对象:
- 通过调用对象的
getClass()
方法获得:
1 | Class classObj = objectName.getClass(); |
- 通过类的隐含静态对象成员变量
class
获得:
1 | Class classObj = ClassName.class; |
- 通过 Class 类的静态方法
forName()
去查找获得。这里必须加上异常处理,因为有可能找不到对应的类。
1 | try { |
获取构造方法
使用 Class 类对象的下面成员方法获取类的构造方法:
方法 | 返回值 | 说明 |
---|---|---|
getConstructors() |
Constructor对象数组 | 返回类的所有public的构造方法 |
getDeclaredConstructors() |
Constructor对象数组 | 返回类的所有构造方法,按声明顺序返回 |
getConstructor(Class<?>... paramTypes) |
Constructor对象 | 返回类的一个public的指定构造方法 |
getDeclaredConstructor(Class<?>... paramTypes) |
Constructor对象 | 返回类的一个指定构造方法 |
举例:
1 | class ClassName1 { |
Constructor 类中的常用方法:
方法 | 说明 |
---|---|
newInstance() |
调用构造器创建一个该类的新实例对象 |
isVarArgs() |
该构造方法是否可以带可变数量的参数,是则返回 true,否则返回 false |
getParameterTypes() |
返回 Class 对象数组,表示该构造方法的参数类型 |
getExceptionTypes() |
返回 Class 对象数组,表示该构造方法可能抛出的异常类型 |
setAccessible(boolean) |
设置为 true 则可以调用非 public 的构造方法来创建对象 |
getModifiers() |
返回一个整数,表示该构造方法的修饰符 |
修饰符的解释
getModifiers() 方法会返回一个整数代表的修饰符,用Modifier类的下面静态方法可以解释修饰符:
方法 | 说明 |
---|---|
isPublic(int) |
是否 public 修饰 |
isProtected(int) |
是否 protected 修饰 |
isPrivate(int) |
是否 private 修饰 |
isStatic(int) |
是否 static 修饰 |
isFinal(int) |
是否 final 修饰 |
toString(int) |
将所有修饰与字符串的形式返回 |
获取和访问成员变量
通过 Class 类对象的下面方法获取成员变量的变量信息:
方法 | 说明 |
---|---|
getField(String) |
返回一个 Field 对象,代表一个 public 的成员 |
getFields() |
返回一个 Field 对象数组,代表所有 public 的成员列表(包括父类的成员) |
getDeclaredField(String) |
返回一个 Field 对象,代表一个的成员 |
getDeclaredFields() |
返回一个 Field 对象数组,代表所有的成员列表(不包括继承的成员) |
Field 类常用的方法有:
方法 | 说明 |
---|---|
get(Object obj) |
返回此 Field 表示的成员对象 |
set(Object obj, Object value) |
将此 Field 表示的成员对象设置为指定值 |
getName() |
获取字段的名称 |
getType() |
返回一个 Class 对象,获取字段的类型 |
getInt(Object obj) |
获取 int 类型的 obj 的成员变量的值 |
setInt(Object obj, int value) |
设置 int 类型的 obj 的成员变量的值 |
getFloat(Object obj) |
获取 float 类型的 obj 的成员变量的值 |
setFloat(Object obj, float value) |
设置 float 类型的 obj 的成员变量的值 |
getBoolean(Object obj) |
获取 boolean 类型的 obj 的成员变量的值 |
setBoolean(Object obj, boolean value) |
设置 boolean 类型的 obj 的成员变量的值 |
setAccessible(boolean) |
设置为 true 则可以访问非 public 的成员 |
getModifiers() |
返回一个整数,表示该成员的修饰符 |
获取和访问方法
通过 Class 类对象的下面方法获取方法信息:
方法 | 说明 |
---|---|
getMethod(String name, Class<?>... paramTypes) |
返回一个 Method 对象,代表一个 public 的方法 |
getMethods() |
返回一个 Method 对象数组,代表所有 public 的方法 |
getDeclaredMethod(String name, Class<?>... paramTypes) |
返回一个 Method 对象,代表一个方法 |
getDeclaredMethods() |
返回一个 Method 对象数组,代表所有的方法(不包括继承的方法) |
Method 类常用的方法有:
方法 | 说明 |
---|---|
invoke(Object obj, Object... args) |
调用 obj 对象的方法 |
getName() |
获取方法名 |
getReturnType() |
返回一个 Class 对象,获取方法的返回值类型 |
getParameterTypes() |
返回 Class 对象数组,获取方法的参数列表的类型的数组 |
getExceptionTypes() |
返回 Class 对象数组,获取方法的可能抛出的类型的数组 |
isVarArgs() |
该方法是否可以带可变数量的参数,是则返回 true,否则返回 false |
getModifiers() |
返回一个整数,表示该方法的修饰符 |
注解 (Annotation)
注解是以结构化的方式为程序提供额外信息,包括能被编译器、加载器、解释器等自动处理的额外信息。
可以进行注解的有:
- 包
- 类型(类、接口、枚举)
- 构造方法
- 方法
- 成员变量
- 参数
- 局部变量
注解类型
是指一种特殊的接口类型,注解
则是指 注解类型
的一个实例。
注解中的信息是以 键 / 值
对的形式存在的,可以存在 0 个或者多个键值对。没有键值对的注解叫标记注解类型。
标准注解
Java 在 API java.lang 包中定义了三个标准的内置注解。如下:
1. @Override
@Override 是一个标记注解类型,用于编译器检查该方法是否是重载方法,可以方式程序员在重写覆盖某个方法时犯错。如果要重写的方法不是父类的方法,则编译器会报错。
2. @Deprecated
@Deprecated 是一个标记注解类型,表示该字段以后版本可能会被废弃,请使用者不应该继续使用,请采用其他方法代替。编译时会有警告提示。但是目前版本还是被使用。
3. @SuppressWarnings
@SuppressWarnings 注解是请编译器不要提示某些类型的警告信息出现。它的用法是传递一个字符串数组作为参数。例如:
1 |
|
元注解
元注解
是对注解进行注解的注解。在 API java.lang.annotation 包中定义了四个标准的元注解。
1. @Documented
@Documented 是一个标记注解类型,被它注解的元素应该被 javadoc 文档化。
2. @Inherited
默认标记在父类上面的注解是不会被子类继承的。@Inherited 表示注解类型会被子类继承。
3. @Retension
表示注解的有效期,也就是注解的保留时间。它的值是一个 java.lang.annotation.RetensionPolicy
的枚举值。该枚举有下面值,表示下面不同的含义:
值 | 说明 |
---|---|
SOURCE |
注解只存在与源文件,编译器解释该注解之后就会丢弃 |
CLASS |
注解会留存在*.class文件中,但是 JVM 不会去读取此注解。默认值 |
RUNTIME |
注解会被 JVM 加载。可以使用反射机制来查询到该注解的内容 |
4. @Target
用于指明注解修饰的对象范围,也就是指明适用的元素类型。如果未设置 @Target,则表示所有程序元素都适用。 它的值是一个 java.lang.annotation.ElementType
的枚举值。该枚举有下面值,表示下面不同的含义:
值 | 说明 |
---|---|
PACKAGE |
注解只标注包 |
TYPE |
注解只标注类、接口、枚举以及 Annotation 类型 |
ANNOTATION_TYPE |
注解只标注 Annotation 类型 |
CONSTRUCTOR |
注解只标注构造方法 |
FIELD |
注解只标注成员 |
METHOD |
注解只标注方法 |
PARAMETER |
注解只标注参数 |
LOCAL_VARIABLE |
注解只标注局部变量 |
自定义注解
自定义注解使用 interface
关键字前面加一个 “@”
来实现,自定义注解隐含继承了 java.lang.annotation.Annotation
接口。有些地方需要注意的是:
- 注解中的方法不需要加上 private、protected、public 等修饰,保持默认即可
- 注解中的方法可以加上 default 来声明默认值
- 自定义注解不能继承其他注解或者接口
- 可以加上元注解来描述注解的使用方式与范围
举例:
1 | package com.testanno; |
通过反射机制访问注解信息
Constructor、Field、Method 类都是继承于 AccessibleObject 类,提供了一下相关的方法:
isAnnotationPresent
: 用于查询是否附加了指定类型的注解getAnnotation
: 获取指定类型的注解对象getAnnotations
: 获取所有的注解对象,返回一个注解对象数组getParameterAnnotations
: 获取所有参数所添加的注解对象,返回一个二维注解对象数组
使用注解例子:
1 | package com.testanno; |
下面例子是通过反射机制来访问注解信息:
1 | package com.testanno; |
输出结果:
1 | Method name = function2 |