Java从入门到精通 第16章 反射

目录

Class类与反射

访问构造方法

访问成员变量

访问方法

使用Annotation功能

定义Annotation类型

访问Annotation信息


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();

        }

    }

}
发布了46 篇原创文章 · 获赞 0 · 访问量 1019

猜你喜欢

转载自blog.csdn.net/weixin_37680513/article/details/103560581