Skip to content

Latest commit

 

History

History
75 lines (62 loc) · 4.25 KB

反射.md

File metadata and controls

75 lines (62 loc) · 4.25 KB

1.反射

反射 Reflection 指的是 Java 程序在运行期可以获取自身的信息,并且可以操作类或对象的内部属性。
反射使 Java 代码可以发现有关已加载类的字段,方法和构造函数信息,并在安全性限制内操作这些字段,方法和构造函数。
反射的核心是 JVM 在运行时才动态加载类或调用方法或访问属性,它不需要事先知道运行对象是谁。
反射的主要功能:

  • 在运行时判断任意一个对象所属的类;
  • 在运行时构造任意一个类的对象;
  • 在运行时得到任意一个类所具有的成员变量和方法;
  • 在运行时调用任意一个对象的所有方法。

反射常见用途:

  • 最重要的用途就是开发各种通用框架,通过配置文件(如 XML 等)加载不同的类或对象,调用不同的方法,运行时动态加载不同的对象;
  • 写测试用例的时候不能改动原有代码中的私有属性,可以通过反射来调用一些 private 方法和字段;
  • 其实我们平时用 IDE 写代码时,当我们输入一个对象或类并想调用它的属性或方法时,点号后就会自动列出它的属性或方法,这里就用到了反射。

2.Class 对象

三种获取方法:

  • Class cls = String.class;
  • String s = "Hello"; Class cls = s.getClass();
  • Class cls = Class.forName("java.lang.String");

JVM 在执行 Java 程序的时候,并不是一次性把所有用到的 class 全部加载到内存,而是第一次需要用到 class 时才加载。

public class Main {
    public static void main(String[] args) {
        if (args.length > 0) {
            create(args[0]);
        }
    }

    static void create(String name) {
        Person p = new Person(name);
    }
}

对于上面的这段代码,当执行 Main.java 时,JVM 首先会把 Main.class 加载到内存。 然而,并不会加载 Person.class,除非程序执行到 create() 方法,JVM 发现需要加载 Person 类时,才会首次加载 Person.class。 如果没有执行 create() 方法,那么 Person.class 根本就不会被加载。

这就是 JVM 动态加载 class 的特性。

动态加载 class 的特性对于 Java 程序非常重要。利用 JVM 动态加载 class 的特性,我们才能在运行期根据条件加载不同的实现类。 例如,Commons Logging 总是优先使用 Log4j,只有当 Log4j 不存在时,才使用 JDK 的 logging

3.字段

获取四种方法:

  • Field getField(name):根据字段名获取某个public的field(包括父类)
  • Field getDeclaredField(name):根据字段名获取当前类的某个field(不包括父类)
  • Field[] getFields():获取所有public的field(包括父类)
  • Field[] getDeclaredFields():获取当前类的所有field(不包括父类)

4.构造方法

获取四种方法:

  • getConstructor(Class...):获取某个public的Constructor
  • getDeclaredConstructor(Class...):获取某个Constructor
  • getConstructors():获取所有public的Constructor
  • getDeclaredConstructors():获取所有Constructor

5.方法

获取四种方法:

  • Method getMethod(name, Class...):获取某个public的Method(包括父类)
  • Method getDeclaredMethod(name, Class...):获取当前类的某个Method(不包括父类)
  • Method[] getMethods():获取所有public的Method(包括父类)
  • Method[] getDeclaredMethods():获取当前类的所有Method(不包括父类)

6.实战

要求:在不改变原来类任意代码的情况下,可以创建任意类对象并执行任意方法。

通过配置文件和反射机制来实现。

优点:在使用一些框架时,不能修改框架里的代码,如果用 new 的方式来实例化对象,在重构时会很繁琐,若仅仅只是修改配置文件就会简单的多。 而且用反射还能达到解耦的效果:若用 new 方式来实例化对象,当该类丢失时编译期间就会报错导致整个项目无法启动;而用反射创建对象,在编译期间仅需要类名字符串,不会报错,不影响其他模块的正常运行。 这也是 Spring 框架中 IOC 控制反转的本质。

代码