[从零开始学习JAVA ] 反射

前言:

Java中的反射是一项强大而灵活的功能,它允许程序在运行时动态地获取、操作和利用类的信息。通过反射,我们可以在运行时检查和修改类的属性、调用类的方法,甚至创建和操作对象实例。这种能力为Java提供了很多灵活性和扩展性,使得我们能够编写更加通用、可插拔和动态的代码。然而,反射也是一种高级特性,需要谨慎使用,因为它可能牺牲了一些性能和类型安全性。在本文中,我们将深入探究Java反射的原理、用法和最佳实践。

反射:

反射是一种在运行时动态获取、检查和操作类的信息的能力。它允许程序在运行时通过类的名称获取其完整结构,并可以实例化对象、调用方法、访问属性和执行其他与类相关的操作,而无需在编译时明确引用这些类。反射的核心是java.lang.reflect包 ,它提供了一组类和接口,用于实现反射功能。使用反射,可以实现一些灵活和通用的编程技术,如动态加载类、配置文件解析、框架扩展和代码生成。然而,反射也会带来性能上的开销,并且破坏了编译时类型检查,因此在使用时需要注意适度和合理性。

也就是说:反射可以把类中的成员变量,成员方法和构造方法单独拿出来进行访问,我们是否会好奇我们自定义类之后,idea为什么会有提示功能?

使用反射的步骤:

1.获取阶段:

在获取阶段,我们使用反射机制来获取与类、方法、字段等相关的信息。这包括获取类的Class对象、构造方法、方法、字段等,并可以检查类的继承关系、接口实现以及注解等元数据信息。获取阶段提供了对类结构的探索和解析的能力,让我们能够动态地获取类的结构信息。

(1)利用反射获取class对象

ini 复制代码
public class test01 {
    public static void main(String[] args) throws ClassNotFoundException {
        //获取class文件:
        //第一种
        Class<?> aClass = Class.forName("Myrflect.student");
        System.out.println(aClass);
 
        //第二种:
        Class<student> studentClass = student.class;
        System.out.println(studentClass);
 
        //第三种:
        student st = new student();
        Class<? extends student> aClass1 = st.getClass();
        System.out.println(aClass1);
 
    }
}

(2)利用反射获得构造方法

ini 复制代码
public class getcontrbute {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
        //1.获取字节码文件对象
        Class<?> aClass = Class.forName("Myrflect.student");
        
        //1.获取公共的构造方法:
        Constructor<?>[] constructors = aClass.getConstructors();
        for (Constructor<?> constructor : constructors) {
            System.out.println(constructor);
        }
        System.out.println("-------------------------");
        
        //2.获取私有的构造方法
        Constructor<?>[] declaredConstructors = aClass.getDeclaredConstructors();
        for (Constructor<?> cons : declaredConstructors) {
            System.out.println(cons);
        }
        System.out.println("-------------------------");
        
        //3.获取单个的构造方法
        Constructor<?> declaredConstructor = aClass.getDeclaredConstructor();
        System.out.println(declaredConstructor);
        Constructor<?> declaredConstructor1 = aClass.getDeclaredConstructor(String.class,int.class,String.class);
        System.out.println(declaredConstructor1);
        
    }
}

(3)反射获取成员变量

ini 复制代码
public class getmember {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        //1.获取Class字节码文件对象
        Class<?> aClass = Class.forName("Myrflect.student");
 
        //1.获取所有公告成员变量对象的数组
        Field[] fields = aClass.getFields();
        for (Field field : fields) {
            System.out.println(field);
        }
        System.out.println("---------------");
        //2.获取所有成员变量对象的数组
        Field[] declaredFields = aClass.getDeclaredFields();
        for (Field field : declaredFields) {
            System.out.println(field);
        }
        System.out.println("---------------");
        //3.获取单个成员变量
        Field name = aClass.getField("name");
        System.out.println(name);
    }
}

(4)反射获取成员方法

ini 复制代码
public class getway {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
        Class<?> aClass = Class.forName("Myrflect.student");
 
        //1.获取所有公共方法对象(包含父类,而每一个类都继承Object类,因此打印会出现很多方法)
        Method[] methods = aClass.getMethods();
        for (Method method : methods) {
            System.out.println(method);
        }
        System.out.println("-----------------------------");
        //2.获取所有方法对象(不包含父类)
        Method[] declaredMethods = aClass.getDeclaredMethods();
        for (Method method : declaredMethods) {
            System.out.println(method);
        }
        System.out.println("-----------------------------");
        //3.获取单个方法
        Method method = aClass.getMethod("getAge");
        System.out.println(method);
 
    }
}

2.使用阶段:

在获取了类的结构信息后,我们可以使用反射机制来动态地实例化对象、调用方法、访问字段等操作。使用阶段利用获取阶段得到的信息,通过反射来操作类的成员,实现灵活、通用和动态的功能。使用阶段可以根据实际需求来动态地操作类的成员,而无需在编译时提前确定具体的类和成员。

csharp 复制代码
public class ReflectionExample {
    public static void main(String[] args) {
        try {
            // 读取和写入字段
            MyClass obj = new MyClass();
            Class<?> clazz = obj.getClass();
            
            // 获取公共字段
            Field publicField = clazz.getField("publicField");
            System.out.println("Public Field Initial Value: " + publicField.get(obj));
            
            // 设置字段的值
            publicField.set(obj, "New Value");
            System.out.println("Public Field Updated Value: " + publicField.get(obj));
            
            // 获取私有字段
            Field privateField = clazz.getDeclaredField("privateField");
            privateField.setAccessible(true); // 设置私有字段可访问
            System.out.println("Private Field Initial Value: " + privateField.get(obj));
            
            // 设置私有字段的值
            privateField.set(obj, 123);
            System.out.println("Private Field Updated Value: " + privateField.get(obj));
            
            // 调用方法
            Method method = clazz.getMethod("publicMethod");
            method.invoke(obj); // 执行公共方法
            
            // 创建对象
            Constructor<?> constructor = clazz.getConstructor();
            Object newObj = constructor.newInstance();
            System.out.println("New Object: " + newObj);
        } catch (NoSuchFieldException | IllegalAccessException | NoSuchMethodException | InvocationTargetException | InstantiationException e) {
            e.printStackTrace();
        }
    }
}

反射还提供了许多其他功能,如获取类的构造方法、接口、父类,获取注解信息等。

需要注意的是,使用反射时要注意权限的限制(如私有成员的访问)以及性能问题(反射操作比直接调用性能较差)。另外,运用反射应尽量遵循设计原则,避免滥用反射,保证代码的可读性和可维护性。

相关推荐
超级小忍14 分钟前
服务端向客户端主动推送数据的几种方法(Spring Boot 环境)
java·spring boot·后端
字节跳跃者16 分钟前
为什么Java已经不推荐使用Stack了?
javascript·后端
字节跳跃者16 分钟前
深入剖析HashMap:理解Hash、底层实现与扩容机制
javascript·后端
程序无bug18 分钟前
Spring IoC注解式开发无敌详细(细节丰富)
java·后端
程序无bug20 分钟前
Spring 对于事务上的应用的详细说明
java·后端
食亨技术团队21 分钟前
被忽略的 SAAS 生命线:操作日志有多重要
java·后端
程序员NEO22 分钟前
精控Spring AI日志
人工智能·后端
考虑考虑38 分钟前
Maven 依赖范围(Scope)
java·后端·maven
张小洛1 小时前
Spring AOP 设计解密:代理对象生成、拦截器链调度与注解适配全流程源码解析
java·后端·spring·spring aop·aop
00后程序员1 小时前
iOS 性能测试工具全流程:主流工具实战对比与适用场景
后端