反射

反射

概述

JAVA反射机制是在运行状态中,对于任意一个类都能够知道这个类的所有属性和方法;对于任意一个对象,都能调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法功能称为Java语言的反射机制。

想要解剖一个类,必须先要获取到该类的字节码文件对象。而而解剖使用的就是Class类中的方法,所以现在要获取到每一个字节码文件对应的Class类型的对象。

获取Class对象

  1. 通过class.forName()来获取Class对象

    1
    Class clazz = Class.forName("com.xx.entity.Emp");
  2. 通过类名.class来获取

    1
    Class<Emp> class = Emp.class;
  3. 通过对象的getClass()来获取

    1
    Class<? extends Emp> clazz = new Emp().getClass();
  4. 基本数据类型可以通过TYPE的方式获取class

    1
    Class<Integer> type = Integer.TYPE;

推荐第1、2种方式

Class对象方法

1
Class<?> clazz = Class.forName("com.xx.xx.类名");
  • getFields()

    获取成员变量,包括子类、父类,同时只能包含公共的方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    Field[] fields = clazz.getFields();

    for(Field field: fields) {
    // 字段名称
    field.getName();

    // 字段类型
    field.getType();

    // 字段修饰符
    field.getModifiers();
    }
  • getDeclaredFields()

    获取当前类的所有属性,不仅仅是公共访问修饰符,所有的访问修饰符都可以拿到

    1
    2
    3
    4
    Field[] declaredFields = clazz.getDeclaredFields();

    // xx表示该类中的某个字段名
    Field xx = clazz.getDeclaredField("xx");
  • 为对象设值

    假设有一个类Student,含有私有属性address(用private修饰的字段),正常情况下private修饰的属性无法被外界访问,但是通过反射能够为address字段设值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    Class clazz = Class.forName("com.xx.entity.Student");

    // 获取address字段
    Field address = clazz.getDeclaredField("address");

    // 将address字段的访问权限设置为可访问,true表示能访问
    address.setAccessible(true);

    // 为address字段赋值
    Object o = clazz.newInstance();
    address.set(o, "上海市");

    反射在一定程度上破坏了封装性,需要合理使用

  • getMethods()

    获取对象中的普通方法,包含当前对象和父类对象的公共方法

  • getDeclaredMethods()

    获取当前类中的所有方法,包括私有方法

  • getConstructors()

    获取对象所有的公有构造方法,不包含父类构造方法

  • getDeclaredConstructors()

    获取对象的所有构造方法,包括私有,不包含父类构造方法

    1
    2
    3
    4
    5
    6
    7
    8
    Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors();

    // 调用私有的构造方法
    Constructor declaredConstructor = clazz.getDeclaredConstructor(String.class, int.class);

    declaredConstructor.setAccessible(true);

    Object o2 = declaredConstructor.newInstance("参数1", 2);