java基础——反射

什么是反射?

  • 反射核心概念:反射是获取类信息的能力,包括类名、方法名、变量、构造器等。
  • 类信息存储在方法区,反射可以通过三种方式获取类对象:类名.class、Class.forName和对象名.getClass
  • 类信息都是存储在类对象当中
  • 获取类信息是为了使用类信息

反射获取变量示例图:

一  如何获取Class的实例?

  • Class<T>

    获取类型参数对应的Class对象的方法。三种获取方式:

    Class<String> clazz2 = String.class; // 直接通过一个类的静态变量class获取
    、
    Class<?> clazz3 = "abc".getClass(); // 通过对象实例
    
    //如果知道一个类的完整类名,可以通过静态方法Class.forName()获取
    Class<?> clazz = Class.forName("java.lang.String"); // 通过全限定名
    

    一个类的Class实例是在类加载时被创建的,而一个类只会被加载一次一个类的Class实例是在类加载时被创建的,而一个类只会被加载一次,(即Class实例在JVM中是唯一的),所以它的hashCode()值也是唯一的 :

输出结果

    

二  成员变量与成员方法

一、操作成员变量(Fields)

1. 获取字段对象
  • getField(String name):获取公有字段(包括继承的公有字段)

  • getDeclaredField(String name):获取任意声明的字段(包括私有、protected,不包括继承字段)

2. 读写字段值
  • set(Object obj, Object value):设置字段值

  • get(Object obj):获取字段值

代码示例

// 获取 PUBLIC 字段(包括父类继承的)
Field publicField = clazz.getField("fieldName"); 

// 获取任意访问权限的字段(仅当前类声明,不包括继承)
Field anyField = clazz.getDeclaredField("fieldName"); 

// 获取所有声明的字段(私有/公有/保护,不包括继承)
Field[] allFields = clazz.getDeclaredFields(); 

三  操作成员方法(Methods)

1. 获取方法对象
  • getMethod(String name, Class<?>... parameterTypes):获取公有方法

  • getDeclaredMethod(String name, Class<?>... parameterTypes):获取任意声明的方法(包括私有)

2. 调用方法
  • invoke(Object obj, Object... args):调用方法

    • obj:方法所属对象实例

    • args:方法参数

 代码示例

// 获取 PUBLIC 方法(包括父类继承的)
Method publicMethod = clazz.getMethod("methodName", parameterTypes); 

// 获取任意访问权限的方法(仅当前类声明)
Method anyMethod = clazz.getDeclaredMethod("methodName", parameterTypes); 

// 获取所有声明的方法(私有/公有/保护)
Method[] allMethods = clazz.getDeclaredMethods(); 

四 Constructor类

  • 得到类的所有构造方法
Constructor constructors[]=Class.forName("java.lang.String").getConstructors();//先得到类对应的字节码对象,再得到构造方法

得到类中某个具体的构造方法,在getConstructor中传入参数类型所对应的字节码

Constructor constructor=Class.forName("java.lang.String").getCondtructor(String.class)//得到String 类的 带有一个String类型参数的构造方法
Method method = clazz.getDeclaredMethod("methodName", int.class); // 方法名 + 参数类型

暴力反射

  • setAccessible(true):使私有/受保护字段可访问(关键步骤)

       1  如果构造方法、普通方法、字段 被private(私有)修饰,默认情况下,在该类的外部是         不允许被访问的,如果使用暴力反射,即使被private修饰也可以进行操作

       2  通常只在测试、框架开发等特殊场景下使用

  • 如果不设置,访问私有字段会抛出IllegalAccessException

使用示例:

  1. 获取私有成员

    // 获取私有字段
    Field privateField = clazz.getDeclaredField("privateField");
    
    // 获取私有方法
    Method privateMethod = clazz.getDeclaredMethod("privateMethod", parameterTypes);
    
    // 获取私有构造方法
    Constructor<?> privateConstructor = clazz.getDeclaredConstructor(parameterTypes);
  2. 突破访问限制(关键步骤)

    // 解除访问检查(暴力核心)
    privateField.setAccessible(true);   // 字段
    privateMethod.setAccessible(true);  // 方法
    privateConstructor.setAccessible(true); // 构造方法
  3. 执行操作

    // 访问/修改私有字段值
    Object value = privateField.get(targetObject);   // 获取值
    privateField.set(targetObject, newValue);       // 修改值
    
    // 调用私有方法
    Object result = privateMethod.invoke(targetObject, args);
    
    // 实例化私有构造
    Object instance = privateConstructor.newInstance(args);

五 示例详解

构造器操作与对象创建

通过反射获取并调用构造器创建对象:

public static void main(String[] args) throws Exception {
    // 获取Student类对象
    Class clazz = Student.class;
    
    // 1. 无参构造器创建对象
    Constructor c1 = clazz.getDeclaredConstructor();
    Student s1 = (Student) c1.newInstance();
    
    // 2. 带int参数构造器
    Constructor c2 = clazz.getDeclaredConstructor(int.class);
    Student s2 = (Student) c2.newInstance(10);
    
    // 3. 私有构造器(暴力反射)
    Constructor c3 = clazz.getDeclaredConstructor(String.class, int.class, int.class);
    c3.setAccessible(true); // 解除私有封装
    Student s3 = (Student) c3.newInstance("张三", 15, 180);
}
成员变量操作

动态访问和修改字段值(含私有字段):

// 获取并设置私有字段
Field nameField = clazz.getDeclaredField("name");
nameField.setAccessible(true); // 暴力反射解除私有限制
nameField.set(s1, "小花");
System.out.println("s1.name = " + nameField.get(s1));

// 操作公共字段
Field ageField = clazz.getField("age");
ageField.set(s3, 20);
System.out.println("s3.age = " + ageField.get(s3));
成员方法调用

动态调用各类方法(含私有方法):

// 调用公共方法
Method startMethod = clazz.getMethod("start", String.class, Integer.class);
startMethod.invoke(s3, "李四", 30);

// 调用私有方法
Method runMethod = clazz.getDeclaredMethod("run", int.class);
runMethod.setAccessible(true);
runMethod.invoke(s2, 5);

// 调用默认可见性方法
Method stopMethod = clazz.getDeclaredMethod("stop", float.class, char.class);
stopMethod.invoke(s1, 3.5f, 'A');
辅助Student类定义
class Student {
    // 字段定义
    public int age;
    private String name;
    protected int height;
    String sex;
    
    // 构造器
    public Student() {}
    public Student(int age) { this.age = age; }
    private Student(String name, int age, int height) {
        this.name = name;
        this.age = age;
        this.height = height;
    }
    
    // 方法定义
    public void start(String name, Integer age) {
        System.out.println(name + "开始学习,年龄:" + age);
    }
    
    private void run(int speed) {
        System.out.println("私有方法调用:以速度" + speed + "跑步");
    }
    
    void stop(float time, char unit) {
        System.out.println("停止学习于" + time + unit);
    }
}
执行结果验证
s1.name = 小花
s3.age = 20
李四开始学习,年龄:30
私有方法调用:以速度5跑步
停止学习于3.5A
反射核心要点
  1. 暴力反射:通过setAccessible(true)解除私有成员封装

  2. 动态操作:运行时获取类信息,无需编译期依赖

  3. 应用场景

    • 框架设计(如Spring IOC)

    • 动态代理

    • 注解处理器

    • 通用工具类开发

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值