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

    }

相关推荐
勘察加熊人25 分钟前
wpf+c#路径迷宫鼠标绘制
开发语言·c#·wpf
在京奋斗者30 分钟前
spring boot自动装配原理
java·spring boot·spring
小黄人软件1 小时前
C# ini文件全自动界面配置:打开界面时读ini配置到界面各控件,界面上的控件根据ini文件内容自动生成,点保存时把界面各控件的值写到ini里。
开发语言·c#
威视锐科技2 小时前
软件定义无线电36
网络·网络协议·算法·fpga开发·架构·信息与通信
牧歌悠悠2 小时前
【Python 算法】动态规划
python·算法·动态规划
JINX的诅咒2 小时前
CORDIC算法:三角函数的硬件加速革命——从数学原理到FPGA实现的超高效计算方案
算法·数学建模·fpga开发·架构·信号处理·硬件加速器
明天不下雨(牛客同名)3 小时前
为什么 ThreadLocalMap 的 key 是弱引用 value是强引用
java·jvm·算法
lisw053 小时前
DeepSeek原生稀疏注意力(Native Sparse Attention, NSA)算法介绍
人工智能·深度学习·算法
多多*4 小时前
Java设计模式 简单工厂模式 工厂方法模式 抽象工厂模式 模版工厂模式 模式对比
java·linux·运维·服务器·stm32·单片机·嵌入式硬件
Android洋芋4 小时前
C语言深度解析:从零到系统级开发的完整指南
c语言·开发语言·stm32·条件语句·循环语句·结构体与联合体·指针基础