一、反射
1.1 概述
????Java反射机制使我们可以在运行时获取程序自身字段、方法和构造函数等信息。一般情况下对象类型在编译期就确定下来了,但通过反射机制即使在编译期未知的对象我们也可以动态的进行创建以及调用访问其方法属性。
总结:Java反射机制的要点就是在运行期间动态加载类且不需要在编译期确定运行对象。常见的通过反射机制以及给定类的全限定名(全限定名 = 包名 + 类型名)我们就可以获取该类的所有属性和方法。
1.2 Class类
Class 类的实例表示正在运行的 Java 应用程序中的类和接口。
使用反射的前提条件是需要获得其对应的Class对象,通过Class类我们就可以获取关于目标类的相关信息。而每一个类都有其对应的Class对象,程序编译后生成的.class 文件保存了类的相关信息,当类在被第一次使用时就会随着.class 文件被加载到JVM中,接着JVM就会据此生成Class对象。
小结: Class 没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的。程序运行的时候JVM会先检查类对应的class对象是否被加载,如果未加载,JVM根据类名查找.class文件,并将其载入。可参考文章:《Java中Class对象详解》
Class 和 java.lang.reflect ?起对反射提供了?持,java.lang.reflect 类库主要包含了以下三个类:
- Field :可以使? get() 和 set() ?法读取和修改 Field 对象关联的字段;
- Method :可以使? invoke() ?法调?与 Method 对象关联的?法;
- Constructor :可以? Constructor 的 newInstance() 创建新的对象
Java1.6中文文档:《JDK_API_1.6中文文档》—— 提取码:3l1e
二、反射使用场景
利用Java类的这种“自省”能力可以让程序更加灵活。例如:
- 一些IDE通过反射可以将对象的所有方法列出来供我们选择
- 框架中反射同注解结合能大大简化开发
- 可以通过配置文件选择需要加载的类提高程序灵活性
三、常用反射API
1. 获取Class对象
Class clazz = Class.forName(全限定类名);
Classc2 = Test.class;
Test t = new Test();
Class clazz = t.getClass();
2. 获取Constructor
Constructor[] constructors = clazz.getConstructors();
Constructor[] constructors = clazz.getDeclaredConstructors();
Constructor[] constructors = clazz.getConstructor(Class...initArgumentTypes);
Constructor[] constructors = clazz.getDeclaredConstructor(Class...initArgumentTypes);
Object t = clazz.newInstance();
setAccessible(boolean flag);
3. 获取Method
Method[] methods = clazz.getMethods();
Method[] methods = clazz.getDeclaredMethods();
Method[] methods = clazz.getMethod(String methodName, Class...parameterTypes);
Method[] methods = clazz.getDeclaredMethod(String methodName, Class... parameterTypes);
Object invoke(Object obj, Object... arguments);
使用invoke动态的调用方法 1.invoke的第一个参数代表要调用该方法的对象 2.传入的参数 3.如果访问的方法是私有的 需要在前面先调用setAccessible(true)获得访问的权限
4. 获取Field
Field[] fields = clazz.getFields();
Field[] fields = clazz.getDeclaredFields();
Field field = clazz.getField(String fieldName);
Field field = clazz.getDeclaredField(String fieldName);
void set(Object instance, Object value);
Object get(Object instance);
区别:getFields 返回的是申明为public 的属性,包括父类中定义,getDeclaredFields 返回的指定类定义的所有定义(含私有域)的属性,不包括父类的。
5.其他
getModifiers();
String modifier = Modifier.toString(field.getModifiers());
Class type = field.getType();
String name = field.getName();
Annotation[] annotations = clazz.getAnnotations();
method.getAnnotation(Class<T> annotationClass);
field.getAnnotation(Class<T> annotationClass);
Demo instance = clazz.newInstance();
Method get = clazz.getDeclaredMethod("get", String.class);
get.setAccessible(true);
get.invoke(instance, "参数");
四、总结
- 成员变量和成员方法在通过反射使用时需要提供使用者,因为对象可能不一样。
- 暴力反射获取如果要使用就调用setAccessible方法赋值true。
- 反射中大多数异常为找不到指定内容或参数类型不匹配等。
- 注意get…和getDeclared…方法的区别。
- 反射和注解的结合在规模较大的程序中有很大的作用。
- 反射在提高程序扩展性和灵活性的同时也降低了性能,切勿滥用。
end
|