【Java复习之路】反射

一、 什么是反射

       反射是指程序在运行时能够获取其自身结构(如类、接口、字段和方法)的能力。它提供了一种机制,使程序能够在运行时获得关于类及其成员的详细信息,并能直接操作任意对象的内部状态。

二、反射的使用

Java的反射机制主要通过java.lang.reflect包提供的类来实现,其中包括:

  • Class:代表类和接口的元数据
  • FieId:表示类的成员变量(包括静态变量)
  • Method:表示类的方法
  • Constructor:表示类的构造器

获取Class的方式

获取Class方式有三种

  • 通过Class.forName("全类名")
  • 通过类名.class
  • 通过对象名.getClass()
public class ReflectDemo {
    public static void main(String[] args)throws Exception {
        // 1、Class.forName("全类名")
        // 常用
        Class class1 = Class.forName("com.reflect.Student");
        // 2、类名.class
        //当做参数传递
        Class class2 = Student.class;
        // 3、对象名.getClass()
        // 当我们已经有了这个类的对象时,才可以使用
        Student student = new Student();
        Class class3 = student.getClass();
    }
}

获取构造方法

Studeng类

public class Student {
    private String name;
    private Integer age;
    private Student(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
    public Student() {
    }
    private Student(String name) {
        this.name = name;
    }
    public Student(Integer age) {
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

 获取方式

public class ReflectDemo1 {
    public static void main(String[] args)throws Exception {
        Class class1 = Class.forName("com.reflect.Student");

        // 获取所有构造方法---公共
        Constructor[] cons = class1.getConstructors();
        for(Constructor constructor : cons){
            System.out.println("公共---" + constructor);
        }

        // 获取所有构造方法---所有
        Constructor[] cons2 = class1.getDeclaredConstructors();
        for (Constructor constructor : cons2){
            System.out.println("所有---" +constructor);
        }
        // 获取单个构造方法---公共
        Constructor con = class1.getConstructor();
        System.out.println("单个---" +con);

        // 获取单个构造方法---所有---带参数
        Constructor con1 = class1.getDeclaredConstructor(String.class);
        System.out.println("带String参数---" +con1);

        // 获取权限修饰符--- 0-没有 1-public 2-private 4-protected
        Constructor con2 = class1.getDeclaredConstructor(String.class, Integer.class);
        int modifiers = con2.getModifiers();
        System.out.println("权限修饰符---" +modifiers);

        // 获取构造方法的参数
        Parameter[] parameters = con2.getParameters();
        for(Parameter parameter : parameters){
            System.out.println("获取构造方法的参数---" +parameter);
        }
    }
}

以上代码运行结果

获取成员变量

public class ReflectDemo2 {
    public static void main(String[] args) throws Exception {
        Class class1 = Class.forName("com.reflect.Student");

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

        // 获取单个成员变量---所有
        Field name = class1.getDeclaredField("name");
        System.out.println("单个---" + name);

        // 获取权限修饰符
        int modifiers = name.getModifiers();
        System.out.println("权限修饰符---" + modifiers);

        // 获取成员变量的名字
        String n = name.getName();
        System.out.println("成员变量名---" + n);

        // 获取成员变量的类型
        Class<?> type = name.getType();
        System.out.println("类型---" + type);

        // 获取成员变量记录的值
        Student student = new Student("zhangsan",18);
        // 由于name是private的,所以需要暴力反射,临时取消权限校验
        name.setAccessible(true); 
        String o = (String) name.get(student);
        System.out.println("成员变量值---" + o);

        // 修改对象里面记录的值
        name.set(student,"lisi");
        System.out.println(student);

    }

以上代码执行结果

获取成员方法

public class ReflectDemo3 {
    public static void main(String[] args) throws Exception{
        Class class1 = Class.forName("com.reflect.Student");

        // 获取所有的方法对象(包含父类中所有的公共方法)
        Method[] methods = class1.getMethods();
        for(Method method : methods){
            // 输出结果:
            // public boolean java.lang.Object.equals(java.lang.Object) 该方法是Object类的
            // ...
            System.out.println(method);
        }

        // 获取所有的方法对象(不获取父类的方法,可以获取本类的私有方法)
        Method[] methods1 = class1.getDeclaredMethods();
        for(Method method : methods1){
            // 输出结果:
            // public java.lang.Integer com.reflect.Student.getAge()
            // public void com.reflect.Student.setAge(java.lang.Integer)
            // public java.lang.String com.reflect.Student.getName()
            // public java.lang.String com.reflect.Student.toString()
            // public void com.reflect.Student.setName(java.lang.String)
            System.out.println("本类" + method);
        }

        // 获取指定的单一方法
        Method setName = class1.getDeclaredMethod("setName", String.class);
        Method getName = class1.getDeclaredMethod("getName");
        // 输出:public void com.reflect.Student.setName(java.lang.String)
        System.out.println(setName);

        // 获取方法的修饰符
        int modifiers = setName.getModifiers();
        System.out.println(modifiers); // 输出:1

        // 获取方法的形参
        Parameter[] parameters = setName.getParameters();
        for(Parameter parameter : parameters){
            System.out.println(parameter); // 输出:java.lang.String arg0
        }

        // 获取方法的返回值
        Student student = new Student();
        setName.setAccessible(true);
        // 参数一:表示方法的调用者
        // 参数二:"张三"表示在调用方法的时候传递的实际参数
        setName.invoke(student, "张三");
        String result = (String) getName.invoke(student);
        System.out.println(result); // 张三

    }

三、反射的使用场景

  1. 框架开发:许多Java框架(如Spring)都使用了反射机制来简化配置和初始化过程,例如Spring通过反射来自动装配bean。
  2. 动态代理:Java的动态代理机制也是基于反射实现的。通过反射,可以在运行时创建接口的代理实现,如AOP(面向切面编程)等功能。
  3. 工具类库:如Apache Commons BeanUtils使用反射来简化JavaBean的操作、如属性赋值、获取等。

四、反射的优缺点

优点:

  • 灵活性:反射使得程序可以在运行时动态修改和擦好像对象的行为,增强了程序的灵活性。
  • 简化配置:减少了硬编码,使配置更加灵活,便于维护和拓展。

缺点:

  • 安全性问题:比如上面可以使用暴力反射的方式直接获取private修饰的成员,即破坏了面向对象的封装性。
  • 可读性问题:过度使用反射可能导致代码难以理解和维护,适度使用反射为最佳。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值