Java反射机制

前言

  Java反射机制是Java语言提供的一种强大功能,允许在运行时动态检查和操作类的结构。与传统编程方式不同,反射使得程序能够在编译期不确定类型和方法的情况下,对类的构造函数、方法、字段等进行操作。这种灵活性在许多高级编程场景中至关重要,尤其是在框架开发、动态代理、依赖注入、测试工具和序列化等领域。通过反射,开发者可以编写出更加通用、灵活的代码,使应用程序具备更强的动态特性。然而,反射的使用也带来了性能开销和安全性挑战,因此需要在特定场景中慎重考虑。本文将详细探讨Java反射机制的原理、应用场景以及使用中的注意事项,帮助开发者更好地理解和应用这一强大的工具

问题:如果仅仅知道一个类的类名,能否动态得到类的定义信息,包括哪些方法, 属性等?

Java反射的概念

   在运行状态中,在仅知道一个类名时,就可以动态获得类中的信息,创建对象,调用对象成员的机制成为Java反射机制

Java反射的作用

     动态获取类的信息

Java反射主要包括

  1. Class 类型 
  2. Constructor 构造方法 
  3. Method 方法 
  4. Field 属性

Class类型-->获取类的Class对象

第一种:类的途径获取

String classname = "com.kid.javaReflect.User";
Class clazz = Class.forName(classname);

第二种:类名获取

Class clazz2 = User.class; //直接User类获取

第三种:类对象获取

        User user = new User();
        Class clazz3 = user.getClass();

获取构造方法

1.获取类的Class对象

        //使用反射机制时,只知道类的名称
        String classname = "com.kid.javaReflect.User";
        //1.通过类名,获得到类的Class对象
        Class cla = Class.forName(classname);

2.通过类的Class对象获取构造方法

 //获得类中的无参构造方法
       Constructor constructor1 = cla.getConstructor();
 //获得类中的有参构造方法
       Constructor constructor2 = cla.getConstructor(String.class, String.class);

3.创建对象(使用构造方法创建对象)

       //获得类中的构造方法,通过构造方法api中的方法创建对象
       Constructor constructor1 = cla.getConstructor();
       //创建对象
       Object object1 = constructor1.newInstance();
       //创建有参构造方法
       Constructor constructor2 = cla.getConstructor(String.class, String.class);
       //创建有对象
       Object object2 = constructor1.newInstance("admin", "111");

4.获取私有的构造方法(可以获取所有类型的构造方法)

        //虽然可以获取私有的构造方法,但是一般不建议操作私有成员,因为打破了封装性
        cla.getDeclaredConstructor(); //获取类中任意的构造方法,包含私有的
        cla.getDeclaredConstructors(); //获取类中所有的构造方法,包含私有的

Method 方法

Method getMethod(String name, Class... parameterTypes) : 通过指定方法名,参数类型,返回一个Method实例

Method类将类中的方法进行封装,可以动态获得方法的信息

例如 :

  •  getName:获得方法名字
  •  getParameterTypes:获得方法参数类型

除了动态获得方法信息外,Method还能动态调用某一个对象的具体方法

● invoke(Object obj, Object... args) :使用obj调用该方法,参数为args

代码演示:

获取类中的所有方法

   Class clazz = MyClass.class;
   Method[] methods = clazz.getDeclaredMethods();
   for (Method method : methods) {
       System.out.println("方法名:" + method.getName());
   }

调用获取到的方法

Class clazz = MyClass.class;
Object obj = clazz.newInstance();
try {
    Method method = clazz.getDeclaredMethod("privateMethod", int.class);
    method.setAccessible(true);
    method.invoke(obj, 10);
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException e) {
    e.printStackTrace();
}

Field 属性

获得Field实例,都是通过Class中的方法实现

● public Field getField(String name)通过指定Field名字,返回 Field实例.

Field类将类的属性进行封装,可以获得属性的基本信息、属性的值,也 可以对属性进行赋值.

  • getName:返回属性的名字
  • set:设置属性值

代码演示:

        //使用反射机制时,只知道类的名称
        String classname = "com.kid.javaReflect.User";

        //1.通过类名,获得到类的Class对象
        Class cla = Class.forName(classname);
        //2.通过类的Class对象,创建对象
        Object object = cla.newInstance();

获得类中的成员变量

        //获得类中的成员变量
        //cla.getField("account"); //获得指定名称的公共的成员变量
        Field accountFiled = cla.getDeclaredField("account"); //获得指定名称的成员变量,包含私有的

cla.getField("account")--->拿去公共的变量

cla.getDeclaredField("account") ----> 拿去所有的,包括可以获取私有的成员变量

注:但是拿去私有的成员变量不可以赋值,等操作(因为破坏了封装性),也可以使用代码修改设置

      field.setAccessible(true); //允许访问操作私有属性

模拟MyBatis反射:

    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, InstantiationException {

        /*
         * Java中创建对象的方式
         *  1.new
         *  2.反序列化
         *  3.反射机制
         *  4.对象克隆
         * */
        //使用反射机制时,只知道类的名称
        String classname = "com.kid.javaReflect.User";

        //1.通过类名,获得到类的Class对象
        Class cla = Class.forName(classname);
        //2.通过类的Class对象,创建对象
        Object object = cla.newInstance();
        //获得类中的成员变量
        //cla.getField("account"); //获得指定名称的公共的成员变量
        Field accountFiled = cla.getDeclaredField("account"); //获得指定名称的成员变量,包含私有的
        //accountFiled.set(object,"admin"); 这样会报错,因为不可以拿去私有属性操作
        HashMap map = new HashMap<>();
        map.put("account","admin");
        map.put("passWord","111");
        Field[] declaredFields = cla.getDeclaredFields();
        for (Field field : declaredFields){
            field.setAccessible(true); //允许访问操作私有属性
            field.set(object,map.get(field.getName()));
        }
        System.out.println(object);
    }

Java反射机制_第1张图片

Json简单实现

package com.kid.javaReflect;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class JsonUtil {
    public static String objectToJson(Object object) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {

        Class cla = object.getClass();
        Field[] declaredFields = cla.getDeclaredFields();
        String a = "";
        for (Field field : declaredFields){
            String getMethodName = "get" + field.getName().substring(0,1).toUpperCase()+field.getName().substring(1);
            Method getMethod = cla.getMethod(getMethodName);
            Object value = getMethod.invoke(object);
             a = a + field.getName() + ":" + String.valueOf(value) +" ";
        }
        return a;
    }
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        User user = new User("admin","111");
        System.out.println(objectToJson(user));
    }
}

反射机制的使用场景 

  • 动态加载和调用:根据类名或方法名在运行时加载类、调用方法、访问字段。
  • 框架实现:用于依赖注入(如Spring)、ORM(如Hibernate)等框架中,提供动态配置和操作。
  • 动态代理:创建代理对象并处理方法调用,常用于AOP编程。
  • 通用代码:操作未知类型的对象,编写更灵活的代码。
  • 测试框架:自动发现和调用测试方法,访问私有成员。
  • 处理注解:读取和处理注解,实现框架中的注解驱动逻辑

 感谢大家的观看,本次分享就到这里。希望我的内容能够对您有所帮助。创作不易,欢迎大家多多支持,您的每一个点赞都是我持续更新的最大动力!如有不同意见,欢迎在评论区积极讨论,让我们一起学习、共同进步!如果有相关问题,也可以私信我,我会认真查看每一条留言。期待下次再见!

                                       希望路飞的笑容可以治愈努力路途中的你我!

Java反射机制_第2张图片

博主vx:Dreamkid05 --->欢迎大家和博主讨论问题 

你可能感兴趣的:(java,开发语言)