反射 Reflection
Java的反射是指程序在运行期可以拿到一个对象的所有信息。
它更多地是给工具或者底层框架来使用,目的是在不知道目标实例任何信息的情况下,获取特定字段的值。
Class类
每加载一种class,JVM就为其创建一个Class类型的实例,并关联起来。注意:这里的Class类型是一个名叫Class的class::
public final class Class {
private Class() {
}
}
Class 是一种特殊的类,用来描述各种类信息。
对于未知的类,想知道它到底是谁,就用到了反射:
void printObjectInfo(Object obj) {
Class cls = obj.getClass(); //能知道obj到底是个啥
}
获取Class实例的方法
- 直接通过一个类的静态变量class获取:
Class cls = String.class;
- 用一个实例的getClass()方法获取:
Class cls = s.getClass();
- 通过静态方法Class.forName()获取:
Class cls = Class.forName("java.lang.String");
Class实例在JVM中是唯一的,Class之间可以用==比较。
Class == 与 instanceof的区别
instanceof能匹配到父类;
Class之间的==只能精确匹配本身;
因为通常是面向抽象编程,所以一般用instanceof比较即可。
Integer n = new Integer(123);
boolean b1 = n instanceof Integer; // true,因为n是Integer类型
boolean b2 = n instanceof Number; // true,因为n是Number类型的子类
boolean b3 = n.getClass() == Integer.class; // true,因为n.getClass()返回Integer.class
boolean b4 = n.getClass() == Number.class; // false,因为Integer.class!=Number.class
动态加载 + 反射一种用法
JVM会第一次用到某个class时,才把它加载到内存。这样就能在运行期根据条件加载不同的实现类。
例如Commons Logging优先加载Log4j的代码大概如下:
// Commons Logging优先使用Log4j:
LogFactory factory = null;
if (isClassPresent("org.apache.logging.log4j.Logger")) {
factory = createLog4j();
} else {
factory = createJdkLog();
}
boolean isClassPresent(String name) {
try {
Class.forName(name); //类名存在
return true;
} catch (Exception e) {
return false;
}
}
访问字段
如下方法可以获取类中的字段信息:
Field getField(name):根据字段名获取某个public的field(包括父类)
Field getDeclaredField(name):根据字段名获取当前类的某个field,包括private(