目录
Class类与反射
java.lang.reflect
所有类都继承与Object类,在Object类中定义了一个getClass方法,该方法返回一个类型为Class的对象,利用Class类的对象可以访问的主要信息。getFields()和getMethods()方法依次获得权限为public的成员变量和方法,包含从父类继承的成员变量和方法。getDeclaredFields()和getDeclaredMethods()只获得在本类中定义的所有成员变量和方法。
访问构造方法
通过上面表中构造方法访问,返回Constructor类型的对象或数组。每个Constructor对象代表一个构造方法。利用每个Constructor对象可以操纵相应的构造方法。
package ex16_reflect;
public class Example_01 {
String s;
int i;
int i2;
int i3;
private Example_01() {
}
protected Example_01(String s, int i) {
this.s = s;
this.i = i;
}
public Example_01(String... strings) throws NumberFormatException {
if (0 < strings.length) {
i = Integer.valueOf(strings[0]);
}
if (1 < strings.length) {
i2 = Integer.valueOf(strings[1]);
}
if (2 < strings.length) {
i3 = Integer.valueOf(strings[2]);
}
}
public void print() {
System.out.println("s = " + s);
System.out.println("i = " + i);
System.out.println("i2 = " + i2);
System.out.println("i3 = " + i3);
}
}
//============================================================================
package ex16_reflect;
import java.lang.reflect.Constructor;
public class Main_01 {
public static void main(String[] args) {
Example_01 example = new Example_01("10", "20", "30");
Class<? extends Example_01> exampleC = example.getClass();
Constructor[] declaredConstructors = exampleC.getDeclaredConstructors(); //获得所有构造方法
for (int i = 0; i < declaredConstructors.length; i++) { //遍历所有构造方法
Constructor<?> constructor = declaredConstructors[i];
System.out.println("查看是否允许带有可变数量的参数:" + constructor.isVarArgs()); //是否有可变参数
System.out.println("该构造方法的入口参数类型依次为:");
Class[] parameterTypes = constructor.getParameterTypes(); //获取所有参数类型
for (int j = 0; j < parameterTypes.length; j++) {
System.out.println("" + parameterTypes[j]);
}
System.out.println("该构造方法可能抛出的异常类型为:");
Class[] exceptionTypes = constructor.getExceptionTypes(); //获取所有异常类型
for (int j = 0; j < exceptionTypes.length; j++) {
System.out.println(" " + exceptionTypes[j]);
}
Example_01 example2 = null;
while (example2 == null) {
try {
if (i == 2) {
example2 = (Example_01) constructor.newInstance();
} else if (i == 1) {
example2 = (Example_01) constructor.newInstance("7", 5);
} else {
Object[] parameters = new Object[]{new String[]{"100", "200", "300"}};
example2 = (Example_01) constructor.newInstance(parameters);
}
} catch (Exception e) {
//该构造方法权限为private,默认不允许使用反射利用newInstance()创建对象,先执行setAccessible(true);则允许创建
System.out.println("在创建对象时抛出异常,下面执行setAccessible()方法");
constructor.setAccessible(true);
}
}
if (example2 != null) {
example2.print();
System.out.println();
}
}
}
}
访问成员变量
返回Field类型的对象或数组,每个Field对象代表一个成员变量,利用Filed对象可以操纵相应的成员变量。
package ex16_reflect;
public class Example_02 {
int i;
public float f;
protected boolean b;
private String s;
}
//=========================================================
package ex16_reflect;
import java.lang.reflect.Field;
public class Main_02 {
public static void main(String[] args) {
Example_02 example = new Example_02();
Class exampleC = example.getClass(); //使用getClass()获得Class对象
Field[] declaredFields = exampleC.getDeclaredFields(); //获得所有成员变量
for (int i = 0; i < declaredFields.length; i++) {
Field field = declaredFields[i]; //遍历成员变量
System.out.println("名称为:" + field.getName()); //获取成员变量名称
Class fieldType = field.getType();
System.out.println("类型为:" + fieldType); //获取成员变量类型
boolean isTrue = true;
while (isTrue) {
//如果该成员变量的访问权限为private,则抛出异常,则不允许访问
try {
isTrue = false;
System.out.println("修改前的值:" + field.get(example));
if (fieldType.equals(int.class)) { //判断变量类型是否是int类型
System.out.println("利用方法setInt()修改成员变量的值");
field.setInt(example, 168);
} else if (fieldType.equals(float.class)) { //判断变量类型是否是float类型
System.out.println("利用方法setFloat()修改成员变量的值");
field.setFloat(example, 99.9F);
} else if (fieldType.equals(boolean.class)) {
System.out.println("利用方法setBoolean()修改成员变量的值");
field.setBoolean(example, true);
} else {
System.out.println("利用方法set()修改成员变量的值");
field.set(example, "MWQ"); //可以为各种类型的成员变量赋值
}
System.out.println("修改后的值:" + field.get(example));
} catch (Exception e) {
//String s;权限为private,需要先设置setAccessible()再修改
System.out.println("在设置成员变量时抛出异常,下面执行setAccessible()方法");
field.setAccessible(true);
isTrue = true;
}
}
System.out.println("---------------------------");
}
Field field = declaredFields[3];
try {
field.set(example, "hi");
System.out.println(field.get(example));
field.setAccessible(false); //修改过一次后就一直是true了
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
访问方法
通过getMethod()等方法访问方法时,返回Method()类型的对象和数组。每个Method对象代表一个方法。利用Method对象可以操纵相应的方法。
package ex16_reflect;
public class Example_03 {
static void staticMethod() {
System.out.println("执行staticMethod()方法");
}
public int publicMethod(int i) {
System.out.println("执行publicMethod()方法");
return i * 100;
}
protected int protectedMethod(String s, int i) throws NumberFormatException {
System.out.println("执行protectedMethod()方法");
return Integer.valueOf(s) + i;
}
private String privateMethod(String... strings) {
System.out.println("执行privateMethod()方法");
StringBuffer stringBuffer = new StringBuffer();
for (int i = 0; i < strings.length; i++) {
stringBuffer.append(strings[i]);
}
return stringBuffer.toString();
}
}
//============================================================
package ex16_reflect;
import java.lang.reflect.Method;
public class Main_03 {
public static void main(String[] args) {
Example_03 example = new Example_03();
Class exampleC = example.getClass();
Method[] declaredMethods = exampleC.getDeclaredMethods(); //获取所有方法
for (int i = 0; i < declaredMethods.length; i++) {
Method method = declaredMethods[i]; //遍历方法
System.out.println("名称为:" + method.getName()); //获取方法名称
System.out.println("是否允许带有可变数量的参数:" + method.isVarArgs()); //是否有可变参数
System.out.println("入口参数类型依次为:"); //入口参数类型
Class[] parameterTypes = method.getParameterTypes();
for (int j = 0; j < parameterTypes.length; j++) {
System.out.println(" " + parameterTypes[j]);
}
System.out.println("返回值类型:" + method.getReturnType()); //返回值类型
System.out.println("可能抛出的异常:");
Class[] exceptionTypes = method.getExceptionTypes(); //可能抛出的异常类型
for (int j = 0; j < exceptionTypes.length; j++) {
System.out.println(" " + exceptionTypes[j]);
}
boolean isTrue = true;
while (isTrue) {
//如果方法访问权限为private抛出异常,不允许访问
try {
isTrue = false;
if ("staticMethod".equals(method.getName())) {
method.invoke(example); //执行没有入口参数的方法staticMethod
} else if ("publicMethod".equals(method.getName())) {
System.out.println("返回值为:"
+ method.invoke(example, 168)); //执行方法
} else if ("protectedMethod".equals(method.getName())) {
System.out.println("返回值为:"
+ method.invoke(example, "7", 5)); //执行方法
} else if ("privateMethod".equals(method.getName())) {
Object[] parameters = new Object[]{new String[]{"M", "W", "Q"}}; //定义二维数组
System.out.println("返回值为:"
+ method.invoke(example, parameters)); //执行方法
}
} catch (Exception e) {
//privateMethod()权限为private需要先setAccessible(true);才可以访问
System.out.println("在执行方法时出现异常,执行下面的setAccessible()方法");
method.setAccessible(true);
isTrue = true;
}
}
System.out.println();
}
}
}
使用Annotation功能
定义Annotation类型
- 使用@interface,这个关键字的隐含意思是继承java.lang.annotation.Annotation接口
- 使用@Annotation,设置Annotation类型使用的成员元素种类,使用枚举类ElementType中的枚举常量设置
- 使用@Retention,设置Annotation的有效范围,使用枚举类RetentionPolicy中的枚举常量设置
package ex16_reflect;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.CONSTRUCTOR) //用于构造方法
@Retention(RetentionPolicy.RUNTIME) //在运行时加载Annotation到JVM中
public @interface Constructor_Annotation {
String value() default "默认构造方法"; //定义一个具有默认值的String型成员
}
package ex16_reflect;
import java.lang.annotation.*;
//用于字段、方法、参数
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
//在运行时加载Annotation到JVM中
@Retention(RetentionPolicy.RUNTIME)
public @interface Field_Method_Parameter_Annotation {
String describle(); //定义一个没有默认值的String型成员
Class type() default void.class; //定义一个具有默认值的Class型成员
}
访问Annotation信息
在定义Annotation类型时,@Retention设置为RetentionPolicy.RUNTIME,那么在程序运行时通过反射就可以获取到相关的Annotation信息,如获取构造方法、字段、方法的Annotation信息。
- Constructor、Field、Method均继承了AccessableObject类,在AccessibleObject中定义了3个关于Annotation的方法
- isAnnotationPresent(Class<? extends Annotation> annotationClass); 查看是否添加了指定类型的Annotation
- getAnnotation(Class<T> annotationClass); 获得指定类型的Annotation,存在返回相应对象,不存在返回null
- getAnnotations(); 返回所有Annotation,返回一个数组
- 在Constructor和Method中还定义了方法getParameterAnnotations(); 用来获得所有参数添加的Annotation,将以Annotation类型的二维数组返回,在数组中的顺序与声明顺序相同,没有参数则返回长度为0的数组;未添加Annotation参数用长度为0的嵌套数组占位
在Record类中运用前面定义的Annotation类型@Constructor_Annotation和@Field_Method_Parameter_Annotation.
package ex16_reflect;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Record {
@Field_Method_Parameter_Annotation(describle = "编号", type = int.class)
int id;
@Field_Method_Parameter_Annotation(describle = "姓名", type = String.class)
String name;
@Constructor_Annotation()
public Record() {
}
@Constructor_Annotation("立即初始化构造方法")
public Record(
@Field_Method_Parameter_Annotation(describle = "编号", type = int.class) int id,
@Field_Method_Parameter_Annotation(describle = "姓名", type = String.class) String name) {
this.id = id;
this.name = name;
}
@Field_Method_Parameter_Annotation(describle = "获得编号", type = int.class)
public int getId() {
return id;
}
@Field_Method_Parameter_Annotation(describle = "设置编号")
public void setId(
@Field_Method_Parameter_Annotation(describle = "编号", type = int.class) int id) {
this.id = id;
}
@Field_Method_Parameter_Annotation(describle = "获得姓名", type = String.class)
public String getName() {
return name;
}
@Field_Method_Parameter_Annotation(describle = "设置姓名")
public void setName(
@Field_Method_Parameter_Annotation(describle = "姓名", type = String.class) String name) {
this.name = name;
}
public static void main(String[] args) {
Record record = new Record();
Class recordC = record.getClass();
//========================访问构造方法(Constructor)====================================
System.out.println("=====访问构造方法(Constructor)=======");
Constructor[] declaredConstructors = recordC.getDeclaredConstructors(); //获得所有构造方法
for (int i = 0; i < declaredConstructors.length; i++) { //遍历构造方法
Constructor constructor = declaredConstructors[i];
//判断是否是指定类型的注释
if (constructor.isAnnotationPresent(Constructor_Annotation.class)) {
//获取指定类型的注释
Constructor_Annotation ca = (Constructor_Annotation) constructor
.getAnnotation(Constructor_Annotation.class);
System.out.println(ca.value()); //获得注释信息
}
//获得参数的注释
Annotation[][] parameterAnnotations = constructor.getParameterAnnotations();
for (int j = 0; j < parameterAnnotations.length; j++) {
//获得指定参数注释的长度
int length = parameterAnnotations[j].length;
if (length == 0) { //长度为0表示没有为该参数添加注释
System.out.println("未添加Annotation的参数");
} else {
for (int k = 0; k < length; k++) {
//获得参数的注释
Field_Method_Parameter_Annotation pa =
(Field_Method_Parameter_Annotation) parameterAnnotations[j][k];
System.out.println(" " + pa.describle()); //获得参数描述
System.out.println(" " + pa.type()); //获得参数类型
}
}
}
System.out.println();
}
//============================访问字段(Field)=====================================
System.out.println("=======访问字段(Field)==========");
Field[] declaredFileds = recordC.getDeclaredFields(); //获得所有字段
for (int i = 0; i < declaredFileds.length; i++) {
Field field = declaredFileds[i];
//查看是否具有指定类型的注释
if (field.isAnnotationPresent(Field_Method_Parameter_Annotation.class)) {
//获得指定类型的注释
Field_Method_Parameter_Annotation fa = field
.getAnnotation(Field_Method_Parameter_Annotation.class);
System.out.println(" " + fa.describle()); //获得字段的描述
System.out.println(" " + fa.type()); //获得字段的类型
}
System.out.println();
}
//============================访问方法(Method)及包含参数的Annotation信息================
System.out.println("===访问方法(Method)及包含参数的Annotation信息===");
Method[] methods = recordC.getDeclaredMethods(); //获得所有方法
for (int i = 0; i < methods.length; i++) {
Method method = methods[i];
//查看是否有指定类型的注释
if (method.isAnnotationPresent(Field_Method_Parameter_Annotation.class)) {
//获得指定类型的注释
Field_Method_Parameter_Annotation ma = method
.getAnnotation(Field_Method_Parameter_Annotation.class);
System.out.println(" " + ma.describle()); //获得方法的描述
System.out.println(" " + ma.type()); //获得方法的返回值类型
}
//获得参数的注释
Annotation[][] parameterAnnotations = method
.getParameterAnnotations();
for (int j = 0; j < parameterAnnotations.length; j++) {
int length = parameterAnnotations[j].length;
if (length == 0) {
System.out.println("未添加Annotation的参数");
} else {
for (int k = 0; k < length; k++) {
//获得指定类型的注释
Field_Method_Parameter_Annotation pa =
(Field_Method_Parameter_Annotation) parameterAnnotations[j][k];
System.out.println(" " + pa.describle()); //获得参数描述
System.out.println(" " + pa.type()); //获得参数类型
}
}
}
System.out.println();
}
}
}