反射机制概述

本文详细介绍了Java反射机制,包括其作用、相关类、获取Class的三种方式,以及如何反编译Field、Method、Constructor。通过实例展示了如何通过反射访问和修改对象属性、调用方法以及构造对象。此外,还探讨了获取父类和父接口的方法。

1、反射机制概述

1.1、反射机制有什么用?

​ 通过Java语言中的反射机制可以操作字节码文件(class文件)。

1.2、反射机制相关的类在哪个包下?

​ 反射机制在java.lang.reflect.*包下。

1.3、反射机制相关的重要的类有哪些?

​ java.lang.class:代表整个字节码,代表一个类型。

​ java.lang.reflect.Method:代表字节码中的方法字节码。

​ java.lang.reflect.Constructor:代表字节码中的构造方法字节码。

​ java.lang.reflect.Field:代表字节码中的属性字节码。

2、获取Class的三种方式

/*
第一种:Class c =Class.forName("完整类带包名");
第二种:Class c = 对象.getClass();
第三种:java语言任何一种类型,包括基本数据类型,它都有.class属性。
*/
package com.wcs.reflect;

import java.util.Date;

/** 
 * 使用反射获取类的三种方式
 */
public class ReflectTest01 {
    public static void main(String[] args) {
        /*
        Class.forName()
        静态方法
        方法的参数是一个字符串
        字符串需要的是一个完整类名
        完整类名必须带有包名。java.lang包也不能省略。
         */
        Class c1 = null;
        try {
            c1 = Class.forName("java.lang.String");//代表String.class文件
            Class c2 = Class.forName("java.util.Date");//代表Date类型
            Class c3 = Class.forName("java.lang.Integer");//代表Integer类型
            Class c4 = Class.forName("java.lang.System");//代表System类型
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        //Java中任何一个对象都有一个方法:getClass()
        String s = "abc";
        Class x = s.getClass();//x代表String.class字节码文件,x代表String类型
        System.out.println(x == c1);//true (==判断的是对象的内存地址)

        //第三种方式
        Class z = String.class;
        Class k = Date.class;
        Class f = int.class;
        Class e = double.class;
        System.out.println(x == z);//true
    }
}

3、反编译Field

package com.wcs.field;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

/**
 * 反编译
 * 获取类的属性
 */
public class ReflectTest03 {
    public static void main(String[] args) {
        try {
            //获取整个类
            Class studentClass = Class.forName("com.wcs.field.Student");

            //完整类名 com.wcs.field.Student
            String className = studentClass.getName();
            System.out.println(className);
            //简单类名 Student
            String simpleName = studentClass.getSimpleName();
            System.out.println(simpleName);
            //获取类中所有的public修饰的Field
            Field[] fields = studentClass.getFields();
            System.out.println(fields.length);//1
            //取出这个Filed
            Field f = fields[0];
            String fName = f.getName();
            System.out.println(fName);//no

            //获取所有的Filed
            Field[] fs = studentClass.getDeclaredFields();
            System.out.println(fs.length);//4
            //遍历fs
            for (Field field : fs) {
                System.out.println("=========");
                //获取属性的修饰符列表
                int i = field.getModifiers();
                System.out.println(i);//返回的是一个数字,每个数字是修饰符的代号
                //把数字转换成字符串
                String s = Modifier.toString(i);
                System.out.println(s);
                //获取属性的类型
                Class fType = field.getType();
                String typeName = fType.getName();
                System.out.println(typeName);
                //获取属性的名字
                System.out.println(field.getName());
            }

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

4、通过反射机制访问对象属性

package com.wcs.field;

import java.lang.reflect.Field;

/**
 * 怎么通过反射机制访问一个Java对象的属性?
 * 给属性赋值set
 * 获取属性值get
 */
public class ReflectTest04 {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException {
        //不使用反射机制,怎么访问一个对象的属性?
        Student s = new Student();
        //给属性赋值
        s.no = 1111;
        //读取属性值
        System.out.println(s.no);

        //使用反射机制,怎么去访问一个对象的属性
        Class studentClass = Class.forName("com.wcs.field.Student");
        //obj就是一个Student对象,底层调用无参构造方法
        Object obj = studentClass.newInstance();
        //获取no属性
        Field noFiled = studentClass.getDeclaredField("no");
        //给no属性赋值2222
        noFiled.set(obj, 2222);
        /*
        反射机制虽然让代码变得复杂了,但是为了“灵活”,也是值得的。
         */
        //读取属性的值
        System.out.println(noFiled.get(obj));

        //可以访问私有的属性吗?
        Field nameField = studentClass.getDeclaredField("age");

        //打破封装(不安全)
        // nameField.setAccessible(true);//这样在外部也是可以访问的
        nameField.set(obj, 18);
        System.out.println(nameField.get(obj));//无法访问私有属性
    }
}

5、反编译Method

package com.wcs.method;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

/**
 * 反射Method
 */
public class ReflectTest05 {
    public static void main(String[] args) throws ClassNotFoundException {
        //获取类
        Class studentClass = Class.forName("com.wcs.method.StudentSystem");

        //获取所有的Method (包括私有的)
        Method[] methods = studentClass.getDeclaredMethods();
        //遍历methods
        for (Method method : methods) {
            //获取修饰符列表
            System.out.println(Modifier.toString(method.getModifiers()));
            //获取返回值类型
            System.out.println(method.getReturnType());
            //获取方法名
            System.out.println(method.getName());
            //获取方法的参数类型列表
            Class[] parameterTypes = method.getParameterTypes();
            for (Class parameterType : parameterTypes) {
                System.out.println(parameterType.getSimpleName());
            }
        }

    }
}

6、反射机制调用方法

package com.wcs.method;

import java.lang.reflect.Method;

/**
 * 通过反射机制调用一个对象的方法
 */
public class ReflectTest06 {
    public static void main(String[] args) throws Exception {
        //不使用反射机制
        StudentSystem studentSystem = new StudentSystem();
        studentSystem.login("admin", "123");

        //使用反射机制来调用一个对象的方法
        Class stuClass = Class.forName("com.wcs.method.StudentSystem");
        //创建对象
        Object obj = stuClass.newInstance();
        //获取method
        Method loginMethod = stuClass.getDeclaredMethod("login", String.class, String.class);
        //调用方法
        System.out.println(loginMethod.invoke(obj, "admin", "123"));//true
    }
}

7、反射调用构造方法

package com.wcs.constructor;

import java.lang.reflect.Constructor;

/**
 * 通过反射调用构造方法
 */
public class ReflectTest07 {
    public static void main(String[] args) throws Exception {
        //不使用反射机制
        Vip v1 = new Vip();
        Vip v2 = new Vip(1001, "jack", true);
        System.out.println(v1);
        System.out.println(v2);

        //使用反射机制,调用无参构造方法
        Class vipClass = Class.forName("com.wcs.constructor.Vip");
        Object obj = vipClass.newInstance();

        //调用有参构造方法
        //获取有参构造方法
        Constructor con = vipClass.getDeclaredConstructor(int.class, String.class, boolean.class);
        //调用有参构造方法new对象
        Object newObj1 = con.newInstance(1002, "rose", false);
        System.out.println(newObj1);

        //获取无参构造方法
        Constructor con2 = vipClass.getDeclaredConstructor();
        //使用无参构造new对象
        Object newObj2 = con2.newInstance();
        System.out.println(newObj2);

    }
}

8、获取父类和父接口

package com.wcs.superIn;

/**
 * 通过反射获取父类和父接口
 */
public class ReflectTest08 {
    public static void main(String[] args) throws ClassNotFoundException {
        //String举例
        Class stringClass = Class.forName("java.lang.String");
        //获取String的父类
        Class superclass = stringClass.getSuperclass();
        System.out.println(superclass);
        //获取String类实现的所有接口
        Class[] interfaces = stringClass.getInterfaces();
        for (Class anInterface : interfaces) {
            System.out.println(anInterface);
        }
    }
}
<think> 我们之前已经详细讨论了Java反射机制概述和使用注解开发的方法。现在用户再次询问相同的问题,可能是希望获得更简洁或更深入的总结。根据引用内容,我们可以整理如下: ### Java反射机制概述 Java反射机制允许在运行时动态获取类的元数据(如类名、方法、字段、构造器等)并操作这些元素。核心是通过`Class`对象实现,无需在编译时知道具体类。关键类包括: - `Class`:类的元数据入口 - `Field`:类的字段(包括私有字段) - `Method`:类的方法 - `Constructor`:类的构造器 #### 反射使用步骤: 1. 获取`Class`对象(通过`Class.forName()`、`对象.getClass()`或`类名.class`) 2. 通过`Class`对象获取字段、方法或构造器 3. 操作这些元素(如调用方法、访问字段、创建实例) **优点**:动态性高,支持运行时类型检查、动态加载类等,广泛应用于框架(如Spring的IoC)[^1][^2]。 **缺点**:性能开销大(比直接调用慢10-100倍)[^4],破坏封装性。 ### 使用注解开发的方法 注解(Annotation)为代码添加元数据,结合反射可实现声明式编程。步骤: 1. **定义注解**:使用`@interface`关键字,并通过元注解(如`@Retention`指定保留策略、`@Target`指定作用目标)配置。 ```java @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface MyAnnotation { String value() default ""; } ``` 2. **使用注解**:在类、方法或字段上添加注解。 ```java public class Example { @MyAnnotation("test") public void method() {} } ``` 3. **处理注解**:通过反射读取注解信息并执行逻辑(如Spring扫描`@Component`注入Bean)[^2]。 ```java Method method = obj.getClass().getMethod("method"); if (method.isAnnotationPresent(MyAnnotation.class)) { MyAnnotation ann = method.getAnnotation(MyAnnotation.class); System.out.println(ann.value()); // 输出"test" } ``` ### 关键注意事项 - **性能优化**:缓存反射获取的`Class`、`Method`等对象。 - **安全性**:谨慎使用`setAccessible(true)`访问私有成员。 - **替代方案**:编译时处理注解(如Lombok的APT)避免运行时开销。 ### 相关问题 1. **如何通过缓存优化反射性能?** 2. **Spring框架如何利用反射处理`@Autowired`注解?** 3. **反射在单元测试中如何模拟私有方法调用?** </think> ### Java反射机制概述 Java反射机制允许程序在**运行时**动态解析类的结构(如字段、方法、构造器等),无需在编译时知晓具体类名。其核心是通过`Class`对象操作类的元数据,实现灵活编程[^1][^2]。 #### 核心原理 - **动态加载类**:通过类全限定名获取`Class`对象,例如: ```java Class<?> clazz = Class.forName("com.example.User"); ``` - **动态实例化**:通过`Constructor`创建对象: ```java Object obj = clazz.getConstructor().newInstance(); ``` - **动态调用**:通过`Method`调用方法: ```java Method method = clazz.getMethod("getName"); String result = (String) method.invoke(obj); ``` #### 关键特性 | **特性** | **说明** | **应用场景** | |------------------|-----------------------------------------------|---------------------------| | 动态性 | 运行时决定操作对象 | 插件系统、框架扩展[^2] | | 访问控制突破 | `setAccessible(true)`可操作私有成员 | 单元测试、框架注入[^3] | | 性能开销 | 比直接调用慢10-100倍(需优化)[^3] | 避免高频调用 | --- ### 使用注解开发的方法 注解(Annotation)为代码添加元数据,结合反射实现声明式编程: #### 开发步骤 1. **定义注解**: ```java @Retention(RetentionPolicy.RUNTIME) // 运行时保留 @Target(ElementType.METHOD) // 作用于方法 public @interface Task { String name(); int priority() default 0; } ``` 2. **使用注解**: ```java public class Scheduler { @Task(name = "backup", priority = 1) public void executeBackup() { /* ... */ } } ``` 3. **反射处理注解**: ```java public void processTasks(Object obj) { for (Method method : obj.getClass().getMethods()) { if (method.isAnnotationPresent(Task.class)) { Task task = method.getAnnotation(Task.class); if (task.priority() > 0) { method.invoke(obj); // 动态调用高优先级任务 } } } } ``` #### 实际应用案例 - **依赖注入**:Spring的`@Autowired`通过反射自动装配Bean[^2] - **API路由**:Spring MVC的`@RequestMapping`映射HTTP请求 - **数据校验**:Hibernate的`@NotNull`注解结合反射验证字段 --- ### ️ 注意事项 1. **性能优化**: - 缓存`Class`和`Method`对象(如使用`Map`存储) - 避免循环中频繁反射调用 2. **安全性**: - 限制`setAccessible(true)`的使用范围 - 结合安全管理器检查权限 3. **替代方案**: - 编译时注解处理(APT)如Lombok - 字节码操作库(如ASM) --- ### 相关问题 1. **如何通过缓存`Method`对象优化反射性能?** 2. **Spring框架如何利用反射实现`@Transactional`的事务管理?** 3. **注解处理器(APT)与运行时反射处理的本质区别是什么?** 4. **如何通过反射动态修改`final`字段的值?**
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值