反射------5.26学习小计

一、定义

Java 反射机制,是指在程序运行期间,对任意一个类,都能知道它的所有属性和方法;对任意一个对象,都能调用它的任意方法和属性。

简单说:

  • 正常开发中,我们是 "先有类,再用对象调用方法 / 属性",编译期就确定了。
  • 反射是 "运行时动态获取类的信息、创建对象、调用方法",甚至能直接操作 private 修饰的私有成员。

一句话总结:反射就是运行时动态解剖、操作类的所有资源。

反射是很多框架的底层基础,比如 Spring 的 IOC、MyBatis 的动态代理、ORM 框架的对象映射,核心都是反射。

二、示例

定义测试实体类

复制代码
public class Animal {
    // 四种访问权限成员变量
    private String name = "animal";
    public String sex = "男";
    Integer age = 18;
    protected String color = "黑色";

    // 三种权限构造方法
    public Animal() {
        System.out.println("无参构造");
    }

    // 私有构造方法
    private Animal(String name) {
        System.out.println("私有有参构造");
    }

    // 默认权限构造方法
    Animal(String name, int age) {
        System.out.println("默认权限有参构造");
    }

    // 普通公有方法
    public void show() {
        System.out.println("public 方法 show()");
    }

    // 私有方法
    private void fly() {
        System.out.println("私有方法 fly()");
    }
}

Class是所有反射操作的唯一入口!!!

获取Class对象的三种方式

复制代码
public class ReflectTest {
    public static void main(String[] args) throws ClassNotFoundException {
        // 方式1:Class.forName("全类名") 【框架最常用】
        Class<?> clazz1 = Class.forName("Animal");

        // 方式2:类名.class 【静态获取,简单高效】
        Class<Animal> clazz2 = Animal.class;

        // 方式3:对象.getClass() 【已有对象实例时使用】
        Animal animal = new Animal();
        Class<? extends Animal> clazz3 = animal.getClass();

        // 验证:三个方式获取的是同一个对象
        System.out.println(clazz1 == clazz2); // true
        System.out.println(clazz1 == clazz3); // true
    }
}
获取方式 核心特点 适用场景
Class.forName() 动态加载类,需要捕获异常 读取配置文件、框架动态加载类
类名.class 静态获取,无异常,性能高 普通工具类、固定类操作场景
对象.getClass() 基于已有对象反向获取类信息 运行时动态判断对象类型

三、反射核心API:获取类的所有资源

面试一句话秒杀答案: 带 Declared 只看本类、全包权限;不带 Declared 只看 Public、含父类。

2. 暴力反射 setAccessible(true) 细节

很多同学以为开启暴力反射是"修改权限",其实是误区:

2. 反射中的致命坑点

如果实体类中同时存在 int ageInteger age,反射表现完全不同:

注意:private 资源不开启该方法,直接反射操作会直接报错权限不足

1. getXXX 和 getDeclaredXXX 区别

  • getFields() / getMethods() / getConstructors() 只获取 public 修饰的资源,包含父类继承的公共资源,无法获取本类私有、默认、受保护资源。

  • getDeclaredFields() / getDeclaredMethods() / getDeclaredConstructors() 获取本类中所有权限 的资源(public/protected/default/private),不获取父类任何资源

  • 不会修改源码权限修饰符

  • 只是关闭 Java 语法权限校验

  • 仅在本次反射操作有效,运行结束恢复原有权限规则

  • int :基本数据类型,默认值 0不能为 null,栈内存存储,不属于对象

  • Integer :包装类对象,默认值 null可以为空,堆内存存储

  • 反射获取 int 类型字段:永远不会空,未赋值默认返回 0

  • 反射获取 Integer 类型字段:未赋值默认返回 null,直接调用方法会空指针

四、完整测试代码

复制代码
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class ReflectTest {
    public static void main(String[] args) throws Exception {
        // 1. 获取Class对象
        Class<?> clazz = Class.forName("Animal");
        Animal animal = new Animal();

        // 2. 获取所有成员变量
        System.out.println("==========所有成员变量==========");
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            System.out.println(field);
        }

        // 3. 获取所有成员方法
        System.out.println("==========所有成员方法==========");
        Method[] methods = clazz.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println(method);
        }

        // 4. 获取所有构造方法
        System.out.println("==========所有构造方法==========");
        Constructor<?>[] constructors = clazz.getDeclaredConstructors();
        for (Constructor<?> constructor : constructors) {
            System.out.println(constructor);
        }

        // 5. 暴力反射操作私有变量
        System.out.println("==========暴力反射操作私有资源==========");
        Field nameField = clazz.getDeclaredField("name");
        nameField.setAccessible(true);
        nameField.set(animal, "小狗");
        System.out.println("修改后的私有属性:" + nameField.get(animal));

        // 调用私有方法
        Method flyMethod = clazz.getDeclaredMethod("fly");
        flyMethod.setAccessible(true);
        flyMethod.invoke(animal);
    }
}

五、作业

5.1student.java

复制代码
public class Student {
    // 私有属性
    private String name;
    private final Integer stuId;
    private static String school;

    // 有参构造
    public Student(String name, Integer stuId) {
        this.name = name;
        this.stuId = stuId;
    }

    // 私有无参构造(私有化)
    private Student() {
        this.stuId = 0; // final属性必须在构造器中初始化
    }

    // 普通公有方法
    public void publicMethod() {
        System.out.println("这是一个普通的公有成员方法");
    }

    // 私有自定义方法
    private void privateMethod(String message) {
        System.out.println("这是私有方法,收到消息:" + message);
    }

    // 静态方法
    public static void staticMethod() {
        System.out.println("这是一个静态方法");
    }

    // 为了方便看结果,重写toString
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", stuId=" + stuId +
                ", school='" + school + '\'' +
                '}';
    }
}

5.2 test.java

复制代码
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class ReflectionTest {
    public static void main(String[] args) throws Exception {
        // 1. 获取Class对象
        Class<Student> studentClass = Student.class;

        // 2. 破解私有无参构造,创建实例
        Constructor<Student> privateConstructor = studentClass.getDeclaredConstructor();
        // 暴力反射:关闭访问检查
        privateConstructor.setAccessible(true);
        Student student = privateConstructor.newInstance();
        System.out.println("创建的实例:" + student);

        // 3. 给普通私有属性赋值、读取
        Field nameField = studentClass.getDeclaredField("name");
        nameField.setAccessible(true);
        // 赋值
        nameField.set(student, "张三");
        // 读取
        String nameValue = (String) nameField.get(student);
        System.out.println("name属性值:" + nameValue);

        // 4. 修改final修饰的私有常量属性(进阶考点)
        Field stuIdField = studentClass.getDeclaredField("stuId");
        stuIdField.setAccessible(true);
        // 先去掉final的修饰(反射修改的关键步骤)
        Field modifiersField = Field.class.getDeclaredField("modifiers");
        modifiersField.setAccessible(true);
        modifiersField.setInt(stuIdField, stuIdField.getModifiers() & ~java.lang.reflect.Modifier.FINAL);
        // 修改值
        stuIdField.set(student, 1001);
        Integer stuIdValue = (Integer) stuIdField.get(student);
        System.out.println("stuId(final属性)修改后的值:" + stuIdValue);

        // 5. 修改/获取static静态私有属性
        Field schoolField = studentClass.getDeclaredField("school");
        schoolField.setAccessible(true);
        // 静态属性,obj传null即可
        schoolField.set(null, "中移铁通大学");
        String schoolValue = (String) schoolField.get(null);
        System.out.println("school(static属性)的值:" + schoolValue);

        // 6. 调用私有成员方法、静态私有方法
        // 调用私有成员方法
        Method privateMethod = studentClass.getDeclaredMethod("privateMethod", String.class);
        privateMethod.setAccessible(true);
        privateMethod.invoke(student, "反射调用成功!");

        // 调用公有静态方法(这里题目里的静态方法是公有的,也可以写一个私有的静态方法演示)
        Method staticMethod = studentClass.getDeclaredMethod("staticMethod");
        staticMethod.setAccessible(true);
        staticMethod.invoke(null); // 静态方法,obj传null

        // 最终查看对象状态
        System.out.println("最终Student对象状态:" + student);
    }
}
相关推荐
techdashen4 小时前
在 Fly.io 上使用 Rust 构建远程开发环境:从 Tokio 到 eBPF
开发语言·后端·rust
Yukinaaaa4 小时前
以“轮盘数组”思维彻底搞懂并实现阻塞队列
java·服务器·ide·安全·javaee·阻塞队列·轮盘数组
留白_4 小时前
pandas文件读取与存储
开发语言·python·pandas
夕除4 小时前
AOP 实现 Redis 缓存切面解析
java·开发语言·python
库拉大叔4 小时前
工具调用效率对比实测:GPT-5.5与Gemini 3.5 Flash性能评估
java·前端·人工智能
我是唐青枫4 小时前
Java MyBatis 实战指南:XML 映射、动态 SQL 与数据访问层设计
java·mybatis
摇滚侠4 小时前
Spring 零基础入门到进阶 面向切面 AOP 52-60
java·后端·spring
feifeigo1234 小时前
马尔可夫决策过程(MDP)MATLAB 实现
开发语言·matlab
就改了5 小时前
微服务接口性能优化:CompletableFuture 并行聚合实践
java·微服务·性能优化
攻城狮Soar5 小时前
STL源码解析之list(1)
开发语言·c++