[Java基础]反射技术

反射

反射就是拿到类文件, 然后操作类的成分(成员变量, 方法, 构造器等)

反射具体学什么?

通过加载类文件, 获取类的成分信息, 操作他们

  1. 反射第一步: 加载类,获取类的字节码 (Class对象)
  2. 获取类的构造器: Constructor对象
  3. 获取类的成员变量: Field对象
  4. 获取类的成员方法: Method对象

反射第一步: 加载类,获取类的字节码 (Class对象)

复制代码
public class GetClass {
    public static void main(String[] args) throws ClassNotFoundException {
        // 目标: 获取类的Class对象 (类文件)
        // 1.通过类名获取类: 类.class
        Class c1 = Student.class;
        System.out.println(c1); // class com.itheima.Student

        // 2.通过Class提供的方法获取类: Class.forName("类的全名称")
        Class c2 = Class.forName("com.itheima.Student");
        System.out.println(c2); // class com.itheima.Student

        // 3.通过Object提供的方法获取类: 对象.getClass()
        Student s = new Student();
        Class c3 = s.getClass();
        System.out.println(c3); // class com.itheima.Student

        // 类文件在系统中只有一份, 三种方式拿到的类文件都是同一个class对象
        System.out.println(c1 == c2); // true
        System.out.println(c2 == c3); // true
    }
}

获取类的构造器: Constructor对象

Class提供了从类中获取构造器的方法

使用获取到的构造器: 初始化对象返回

复制代码
public class GetClassInfo {
    public static void main(String[] args) throws Exception {
        // 目标: 通过反射获取类的所有信息
        // 1.获取类文件的信息
        getClassInfo();
        // 2.获取类的构造器
    }

    // 2.获取类的构造器
    private static void getConstructors() throws Exception {
        Class c1 = Student.class;
        // 2.1获取类的全部构造器
        Constructor[] sons = c1.getDeclaredConstructors();
        for (Constructor son : sons) {
            System.out.println(son.getName() + "(" + son.getParameterCount() + "个参数)");
        }

        // 2.2获取单个构造器
        Constructor son = c1.getDeclaredConstructor(); // 获取无参构造器
        System.out.println(son.getName() + "(" + son.getParameterCount() + "个参数)");

        Constructor son2 = c1.getDeclaredConstructor(String.class, int.class); // 获取有参构造器
        System.out.println(son2.getName() + "(" + son2.getParameterCount() + "个参数)");

        // 2.3获取构造的作用就是创建对象
        Student s1 = (Student) son.newInstance();
        System.out.println(s1);

        // 2.4暴力反射 可以访问私有的构造器,成员变量和方法
        son2.setAccessible(true);
        Student s2 = (Student) son2.newInstance("张三", 19);
        System.out.println(s2);
    }

    // 1.获取类文件的信息
    private static void getClassInfo() {
        Class c1 = Student.class;
        System.out.println(c1.getName()); // 获取类的全类名 com.itheima.Student
        System.out.println(c1.getSimpleName()); // 获取类的简类名 Student
    }
}

获取类的成员变量: Field对象

Class提供了从类中获取成员变量的方法

为成员变量取值/赋值

复制代码
public class GetClassInfo {
    public static void main(String[] args) throws Exception {
        // 目标: 通过反射获取类的所有信息
        // 3.获取类的成员变量
        getFields();
        // 4.获取类的成员方法
        getMethods();

    }

    // 3.获取类的成员变量
    private static void getFields() throws Exception {
        Class c1 = Student.class;
        // 3.1获取类的全部成员变量
        Field[] fields = c1.getDeclaredFields();
        for (Field field : fields) {
            System.out.println(field.getName() + "(" + field.getType().getName() + ")");
        }

        // 3.2获取单个成员变量
        Field name = c1.getDeclaredField("name"); // 获取name成员变量
        System.out.println(name.getName() + "(" + name.getType().getName() + ")");

        Field age = c1.getDeclaredField("age");
        System.out.println(age.getName() + "(" + age.getType().getName() + ")");

        // 3.3获取成员变量的作用就是取值赋值
        Student student = new Student(); // 得到学生对象
        name.setAccessible(true); // 暴力反射: 绕过访问权限修饰符
        name.set(student, "李四"); // 变量赋值
        age.set(student, 18); // 变量赋值

        String sname = (String) name.get(student); // 变量取值
        int sage = (int) age.get(student); // 变量取值
    }
}

获取类的成员方法: Method对象

Class提供了从类中获取成员方法的API

执行获取到的方法

复制代码
package com.itheima;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class GetClassInfo {
    public static void main(String[] args) throws Exception {
        // 目标: 通过反射获取类的所有信息
        // 4.获取类的成员方法
        getMethods();

    }

    // 4.获取类的成员方法
    private static void getMethods() throws Exception {
        Class c1 = Student.class;
        // 4.1获取类的全部成员方法
        Method[] methods = c1.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println(method.getName() + "(" + method.getParameterCount() + "个参数)");
        }

        // 4.2获取单个成员方法
        Method method = c1.getDeclaredMethod("setName", String.class); // 获取setName方法
        System.out.println(method.getName() + "(" + method.getParameterCount() + "个参数)");

        // 4.3获取成员方法的目的就是执行该方法
        Student student = new Student();
        method.setAccessible(true); // 暴力反射: 绕过访问权限修饰符
        method.invoke(student, "张三"); // 执行setName方法
    }

}

反射的作用

  1. 可以得到一个类的全部成分然后操作。

  2. 可以破坏封装性。

  3. 可以绕过泛型的约束

  4. 主流的框架都会基于反射设计出一些通用的功能。

    public class Demo {
    public static void main(String[] args) throws Exception {
    // 目标: 了解反射的作用
    ArrayList<String> list = new ArrayList<>();
    list.add("张无忌");
    list.add("令狐冲");
    list.add("东方不败");

    复制代码
         // 通过反射绕过泛型的约束
         Class c1 = list.getClass();
         Method add = c1.getDeclaredMethod("add",Object.class);
         add.invoke(list,98);
         add.invoke(list,true);
    
         System.out.println(list); // [张无忌, 令狐冲, 东方不败, 98, true]
     }

    }

案例

需求: 对于任意一个对象,该框架都可以把对象的字段名和对应的值,保存到文件中去

  1. 定义一个方法, 接收任意对象

  2. 通过反射获取对象的Class对象, 然后获取全部的成员变量

  3. 遍历成员变量, 然后提取成本成员变量的值

  4. 把成员变量名, 变量值, 写入到文件中

    public class Demo {
    public static void main(String[] args) throws Exception {
    // 反射是框架的核心技术
    Dog dog = new Dog("哈士奇", 4);
    Student student = new Student("小明", 19, 100);

    复制代码
         SaveObjectFrameWork.saveObject(dog); // 保存dog对象到文件中
         SaveObjectFrameWork.saveObject(student); // 保存student对象到文件中
     }

    }

    public class SaveObjectFrameWork {
    // 保存任意对象的静态方法
    public static void saveObject(Object obj) throws Exception {
    // 打印流
    PrintStream ps = new PrintStream(new FileOutputStream("day8-reflect\src\com\itheima\test3\obj.txt", true));

    复制代码
         // 获取类文件
         Class c = obj.getClass();
         String simpleName = c.getSimpleName();
         ps.println("==========" + simpleName + "==========");
         // 获取所有的成员变量
         Field[] fields = c.getDeclaredFields();
         for (Field field : fields) {
             String fieldName = field.getName(); // 获取变量名
             field.setAccessible(true); // 暴力反射, 绕过权限修饰符
             Object fileValue = field.get(obj); // 获取变量值
             ps.println(fieldName + "=" + fileValue);
         }
         ps.close();
     }

    }

相关推荐
Spirit_NKlaus2 分钟前
解决HttpServletRequest无法获取@RequestBody修饰的参数
java·spring boot·spring
不死的精灵9 分钟前
【Java21】在spring boot中使用ScopedValue
java·spring boot·后端
liulilittle19 分钟前
深度剖析:OPENPPP2 libtcpip 实现原理与架构设计
开发语言·网络·c++·tcp/ip·智能路由器·tcp·通信
88号技师26 分钟前
2025年6月一区-田忌赛马优化算法Tianji’s horse racing optimization-附Matlab免费代码
开发语言·算法·matlab·优化算法
勤奋的知更鸟32 分钟前
Java 编程之模板方法模式
java·开发语言·模板方法模式
逸风尊者1 小时前
开发易掌握的知识:GeoHash查找附近空闲车辆
java·后端
ゞ 正在缓冲99%…1 小时前
leetcode918.环形子数组的最大和
数据结构·算法·leetcode·动态规划
碎叶城李白1 小时前
若依学习笔记1-validated
java·笔记·学习·validated
上单带刀不带妹1 小时前
手写 Vue 中虚拟 DOM 到真实 DOM 的完整过程
开发语言·前端·javascript·vue.js·前端框架
Kaltistss2 小时前
98.验证二叉搜索树
算法·leetcode·职场和发展