关于动态语言:
一般而言,开发者社群说到动态语言,大致认同的一个定义是:“程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言”。从这个观点看,Perl,Python,Ruby是动态语言,C++,Java,C#不是动态语言。
Java中的反射机制:
Java中的反射机制指的是在程序运行时,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。Java程序可以加载一个运行时才得知名称的Class,并获得其除了方法的定义的完整构造,并生成对象实体,或对其fields设值或调用其methods。
Java反射机制提供的功能:
在运行时判断任意一个对象所属的类在运行时构造任意一个类的对象 在运行时判断任意一个类所具有的成员变量和方法 在运行时调用任意一个对象的方法 生成动态代理
篇外话:
Spring框架中的Ioc使用工厂模式和Java的反射机制;AOP使用了代理模式。
实现Java反射机制的相关类:(位于java.lang.reflect包中)
1 | Class Field Method Constructor Array |
Class类介绍:
Class类描述Java程序运行时的所有Classes和interfaces,同时也用来描述enum、array、Java基本数据类型。
生成Class:
当一个class文件被加载或者类加载器的defineClass()被JVM调用时,JVM便自动产生一个Class 对象。
反射机制常用的API
生成Class对象的方法:
① 根据完整类名获取类,调用Class的静态方法forName():
1 | Class<?> classType = Class.forName(“java.lang.String”); |
② 通过类名获取,使用class语法,这里ReflectionTest为一个类名:
1 | Class<?> classType = ReflectionTest.class; |
③ 通过对象的getClass()方法获取:
1 | User user = new User(); |
④ 对于包装类的Class的获取,使用包装类的TYPE语法:
1 | Class classType = Integer.Type; |
创建反射获取的类的实例的方法:
① 调用Class的newInstance()方法:
1 | Object reflectionText = classType.newInstance(); |
② 通过Class获取构造方法再实例化:
1 | Object user2 = classType.getConstructor(new Class[]{}).newInstance(new Object[]{}); |
当Class数组为空时,本质上等价于①,即调用无参构造函数
获取Class对象的方法:
① 获取所有方法:
1 | Method[] methods = classType.getMethods(); |
② 获取指定方法:
1 | Method setter = classType.getMethod(methodName, new Class[]{}); |
其中methodName为方法名,后面的Class数组为方法的参数表。
执行获取的方法:
1 | Object result = setter.invoke(reflectionText, new Object[]{"http://www.itzhai.com"}); |
其中reflectionText为反射获取的类的实例,Object[]为传进方法的参数表。
获取Class对象的域:
获取所有的域,包括公共、保护、默认(包)访问和私有域,但不包括继承的域:
Field[] fields = classType.getDeclaredFields();
获取指定的域,返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段:
1 | Field field = classType.getDeclaredField("fieldName"); |
设置压制访问控制检查,这样就可以获取和设置私有域的值了:
1 | field.setAccessible(true); |
获取指定的域,只能返回public类型的域:
1 | Field field = classType.getField("fieldName"); |
获取某个对象的域的对应值:
1 | Field field = classType.getField("fieldName"); |
设置某个对象的域的对应值:
1 | Field field = classType.getField("fieldName"); |