Java 类的反射

Java 类的反射

 

1、简述

        JAVA反射(Reflection)机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。一个类有:成员变量、方法、构造方法、包等等信息,利用反射技术可以对一个类进行解剖,把一个个组成部分映射成一个个对象,要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法,所以先要获取到每一个字节码文件对应的Class类型的对象。

 想要了解反射就不得不了解一下《java类的生命周期与类加载器》

反射常用的类
  • ClassClass 类的实例表示正在运行的 Java 应用程序中的类和接口的Class对象信息。
  • Constructor:关于类的单个构造方法的信息以及对它的权限访问。
  • Field:Field 提供有关类或接口的单个字段的信息,以及对它的动态访问权限。
  • Method:Method 提供关于类或接口上单独某个方法的信息。
      

2、反射的使用示例

2.1、构造方法调用示例:

/**
 * @Author dw
 * @ClassName Student
 * @Description 构造方法反射使用
 * @Date 2023/4/23 21:54
 * @Version 1.0
 */
public class Student {

    // 无参构造方法
    public Student() {
        System.out.println("调用了公有、无参构造方法执行了。。。");
    }

    // 有一个参数的构造方法
    public Student(char name) {
        System.out.println("姓名:" + name);
    }

    // 有多个参数的构造方法
    public Student(String name, int age) {
        System.out.println("姓名:" + name + "年龄:" + age);
    }

    // 受保护的构造方法
    protected Student(boolean n) {
        System.out.println("受保护的构造方法 n = " + n);
    }

    // 私有构造方法
    private Student(int age) {
        System.out.println("私有的构造方法   年龄:" + age);
    }

// 测试
public static void main(String[] args) throws Exception { // 1.加载Class对象 Class clazz = Student.class; // 2.获取所有公有构造方法 System.out.println("**********************所有公有构造方法*********************************"); Constructor[] conArray = clazz.getConstructors(); for (Constructor c : conArray) { System.out.println(c); } System.out.println("************所有的构造方法(包括:私有、受保护、默认、公有)***************"); conArray = clazz.getDeclaredConstructors(); for (Constructor c : conArray) { System.out.println(c); } System.out.println("*****************获取公有、无参的构造方法*******************************"); Constructor con = clazz.getConstructor(); System.out.println("con = " + con); // 调用构造方法 Object obj = con.newInstance(); System.out.println("******************获取私有构造方法,并调用*******************************"); Constructor privateCon = clazz.getDeclaredConstructor(int.class); System.out.println(privateCon); // 暴力访问(忽略掉访问修饰符) privateCon.setAccessible(true); obj = privateCon.newInstance(28); } }

 

2.2、获取成员变量并调用

/**
 * @Author dw
 * @ClassName Student
 * @Description 反射调用成员变量
 * @Date 2023/4/23 21:54
 * @Version 1.0
 */
public class Student {
    public String name;
    protected int age;
    char sex;
    private String phoneNum;

    @Override
    public String toString() {
        return "Student [name=" + name + ", age=" + age + ", sex=" + sex
                + ", phoneNum=" + phoneNum + "]";
    }

    // 测试
    public static void main(String[] args) throws Exception {
        // 1.获取Class对象
        Class stuClass = Student.class;
        // 2.获取字段
        System.out.println("************获取所有公有的字段********************");
        Field[] fieldArray = stuClass.getFields();
        for (Field f : fieldArray) {
            System.out.println(f);
        }
        System.out.println("************获取所有的字段(包括私有、受保护、默认的)********************");
        fieldArray = stuClass.getDeclaredFields();
        for (Field f : fieldArray) {
            System.out.println(f);
        }
        System.out.println("*************获取公有字段**并调用***********************************");
        Field f = stuClass.getField("name");
        System.out.println(f);
        // 获取一个实例化的student对象, 相当于 new Student();
        Object obj = stuClass.getConstructor().newInstance();
        // 为字段设置值 为Student对象中的name属性赋值--》stu.name = "刘德华"
        f.set(obj, "刘德华");
        //验证
        Student stu = (Student) obj;
        System.out.println("验证姓名:" + stu.name);

        System.out.println("**************获取私有字段****并调用********************************");
        f = stuClass.getDeclaredField("phoneNum");
        System.out.println(f);
        f.setAccessible(true);//暴力反射,解除私有限定
        f.set(obj, "18888889999");
        System.out.println("验证电话:" + stu);
    }
}

 

2.3、获取成员方法并调用 

/**
 * @Author dw
 * @ClassName Student
 * @Description 反射调用成员方法
 * @Date 2023/4/23 21:54
 * @Version 1.0
 */
public class Student {
    public void show1(String s) {
        System.out.println("调用了:公有的,String参数的show1(): s = " + s);
    }

    protected void show2() {
        System.out.println("调用了:受保护的,无参的show2()");
    }

    void show3() {
        System.out.println("调用了:默认的,无参的show3()");
    }

    private String show4(int age) {
        System.out.println("调用了,私有的,并且有返回值的,int参数的show4(): age = " + age);
        return "abcd";
    }

    // 测试
    public static void main(String[] args) throws Exception {
        // 1.获取Class对象
        Class stuClass = Student.class;
        // 2.获取所有公有方法
        System.out.println("***************获取所有的”公有“方法*******************");
        Method[] methodArray = stuClass.getMethods();
        for (Method m : methodArray) {
            System.out.println(m);
        }
        System.out.println("***************获取所有的方法,包括私有的*******************");
        methodArray = stuClass.getDeclaredMethods();
        for (Method m : methodArray) {
            System.out.println(m);
        }
        System.out.println("***************获取公有的show1()方法*******************");
        // 参数1:方法名称, 参数2:方法对应的形式参数类型
        Method m = stuClass.getMethod("show1", String.class);
        System.out.println(m);
        // 实例化一个Student对象
        Object obj = stuClass.getConstructor().newInstance();
// 调用方法, 第一个参数:实例化后的对象(如果调用的是静态方法,可以是null), 第二个参数:调用的方法的形参 m.invoke(obj,
"刘德华"); System.out.println("***************获取私有的show4()方法******************"); m = stuClass.getDeclaredMethod("show4", int.class); System.out.println(m); // 解除私有限定 m.setAccessible(true); Object result = m.invoke(obj, 20); System.out.println("返回值:" + result); } }

 

3、反射的使用总结

1、获取类的 Class 对象实例。 三种方式任选其一:

Class c1 = Class.forName("com.dw.study.Study")
Class c1 = new Study().getClass()
Class c1 = Study.class;

2、根据 Class 对象实例获取 Constructor 对象。

Constructor constructor = c1.getConstructor();

3、使用 Constructor 对象的 newInstance()方法获取反射类对象。

Object newInstance = constructor.newInstance();

4、而如果要调用某一个方法,则需要经过下面的步骤:
4.1、获取方法的 Method 对象

Method setPriceMethod = c1.getMethod("setPrice", int.class);

4.2、利用 invoke 方法调用方法

setPriceMethod.invoke(newInstance, 14);

 

 

4、工具类

/**
 * @Author dw
 * @ClassName ClassUtils
 * @Description 反射操作工具
 * @Date 2023/2/14 14:05
 * @Version 1.0
 */
public class ClassUtils {

    /**
     * 根据字段名称获取对象值
     *
     * @param object
     * @param fieldName
     * @return
     */
    private static Object getValue(Object object, String fieldName) {
        try {
            Field field = object.getClass().getDeclaredField(fieldName);
            field.setAccessible(true);
            return field.get(object);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 根据字段名称设置对象值
     * @param t
     * @param fieldName
     * @param value
     * @param <T>
     */
    public static <T> void setValue(T t, String fieldName, Object value) {
        try {
            Class<T> tClass = (Class<T>) t.getClass();
            Field declaredField = tClass.getDeclaredField(fieldName);
            declaredField.setAccessible(true);
            declaredField.set(t, value);
        } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

 

 

 

 

 

posted @ 2018-08-15 19:27  邓维-java  阅读(390)  评论(0编辑  收藏  举报