Java 反射

虽然Java不是动态语言1,但Java语言具有一定的动态性,可以利用反射机制,字节码操作获得类似动态语言的特性,Java的动态性让编程更加灵活。
反射:指的是可以在程序运行时加载、探知、使用编译期间完全未知的类。加载完类之后,在堆内存中,就产生了一个 Class 类型的对象(一个类只有一个 Class 对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,形象的称为反射。
反射机制的作用:重点在于动态性:动态加载类、动态获取类的信息(属性、方法、构造器);动态创建对象;动态调用方法、构造器;动态处理属性;此外还能处理泛型、注解。
获取Class对象:

  1. Class.forName();(常用)

  2. getClass();

  3. .class;

    代码:

  • javaBean:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    public class User {
    private int id;
    private int age;
    private String name;
    //javabean一定要有无参构造器
    public User() {
    }
    public User(int id, int age, String name) {
    super();
    this.id = id;
    this.age = age;
    this.name = name;
    }
    public int getId() {
    return id;
    }
    public void setId(int id) {
    this.id = id;
    }
    public int getAge() {
    return age;
    }
    public void setAge(int age) {
    this.age = age;
    }
    public String getName() {
    return name;
    }
    public void setName(String name) {
    this.name = name;
    }
    }
  • 获得User类的反射对象:
    1
    2
    3
    4
    5
    6
    7
    String path = "com.sxt.test.bean.User";
    Class clazz = Class.forName(path);//方法一

    User u = new User();
    Class clazz2 = u.getClass();//方法二

    Class clazz3 = com.sxt.test.bean.User.class;//方法三
  • 获得User类的属性:
    1
    Field f = clazz.getDeclaredField("name");
  • 获得User类的方法:
    1
    2
    3
    Method m01 = clazz.getDeclaredMethod("getName", null);
    //如果方法有参数,则必须传递参数类型对应的Class对象
    Method m02 = clazz.getDeclaredMethod("setName", String.class);
  • 获得User类指定的构造器:
    1
    Constructor constructor = clazz.getDeclaredConstructor(int.class,int.class,String.class);
  • 通过反射API动态的操作:构造器,方法,属性:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    //通过反射API调用构造方法,构造对象
    User u1 = (User) clazz.getConstructor().newInstance();//调用了User的无参构造器
    User u2 = (User)clazz.getConstructor(int.class,int.class,String.class).newInstance(1001,18,"席博");//调用了User带参构造器

    //通过反射API调用普通方法 invoke(对象,参数)方法
    User u3 = (User) clazz.getConstructor().newInstance();
    Method method = clazz.getDeclaredMethod("setName", String.class);
    method.invoke(u3, "aaa");//u3.setName("aaa");

    //通过反射API操作属性
    User u4 = (User) clazz.getConstructor().newInstance();
    Field f = clazz.getDeclaredField("name");//通过反射获得属性
    f.setAccessible(true); //这个属性不需要做安全检查,可以直接访问
    f.set(u4, "bbb"); //通过反射直接写u4属性
    f.get(u4);//通过反射读取u4属性
  • 通过反射读取泛型的信息:ParameterizedType: 表示一种参数化的类型,比如Collection
  • 通过反射读取注解的信息,模拟处理注解信息的流程,具体参见:Java 注解

反射的性能问题:使用反射性能会降低(约30倍),setAccessible:启用和禁用访问安全检查的开关,设为 true 则表示反射的对象在使用时禁止 Java 语言访问检查。禁止安全检查,可以提高反射的运行速度(大约提高四倍)。


  1. 1.动态语言:程序运行时,可以改变程序结构或变量类型。常见的动态语言:Python、ruby、javascript