问:什么是 java 的反射?
答:反射是在运行时而非编译时动态获取类型的信息(譬如接口信息、成员信息、方法信息、构造方法信息等)然后依据这些动态获取到的信息创建对象、访问修改成员、调用方法等。
通过调用 Class.forName(class)
方法可以访问返回一个以指定字符串 class 为类名的类对象,因为 java 里面任何 class 都要装载在虚拟机上才能运行,所以那个方法的作用就是装载类用的,也可以直接通过 类名.Class
获取 Class 类对象,还可以通过实例.getClass() 方法获取 Class 类对象;
Class 类提供了许多方法,譬如可以获取与类名称有关的信息,可以获取类中定义的字段 Field(静态和实例变量都被称为字段,可获取 public 与非 public 的字段)、Field 也提供了许多获取字段或者设置字段具体信息的操作,可以获取类中定义的方法 Method(静态方法和非静态方法都是方法,可获取 public 与非 public 的方法)、Method 也提供了许多获取方法信息、修饰符、参数、返回值、注解等、调用对象方法的操作;
Class.newInstance()
方法可以创建对象实例(只是用默认无参构造),不过也提供了一些其他方法获取所有构造方法;
Class 还提供了类型检查、类型判断、修饰符、父类、接口、注解、内部类等操作的方法。
从 JVM 的角度使用关键字 new 创建一个类的时候这个类可以没有被加载,但是使用 newInstance()
方法的时候就必须保证这个类已经加载且这个类已经连接了,而完成上面两个步骤是 Class 的静态方法 forName()
所完成的,这个静态方法调用了启动类加载器(即加载 java API 的那个加载器),所以 newInstance()
实际上是把 new 这个方式分解为两步,即首先调用 Class 加载方法加载某个类然后实例化。
问:简单说说 java 反射的作用?
答:
反射可以在运行时判断任意一个对象所属的类;
在运行时判断任意一个类所具有的成员变量和方法;
在运行时调用任意一个对象的方法;
在运行时构造任意一个类的对象;
生成动态代理操作。
问:如何提高反射的效率?反射优缺点有哪些?
答:提高反射效率要考虑的问题如下,
首先保证反射 API 最小化,譬如尽量使用
getMethod()
直接获取而不是getMethods()
遍历查找获取;其次需要多次动态创建一个类的实例时尽可能地使用缓存。
反射虽然很灵活,有些时候能够使得写的代码变的大幅精简,但是在用的时候一定要注意具体的应用场景,因为反射的优点是能够运行时动态获取类的实例,大大提高系统的灵活性和扩展性,与 Java 动态编译相结合可以实现无比强大的功能;而其缺点就是性能相对较低,此外使用反射相对来说不安全,破坏了类的封装性(可以通过反射获取这个类的私有方法和属性),有些情况下反射受版本兼容问题而不稳定(譬如 Android 不同 ROM API 的修改)而难以提前发现问题。