引入
动态编程语言
变量并不是在计算机内存中被写入的某个值,它们只是指向内存的“标签”和“名称”,所以动态编程语言的变量没有一个固定的类型。Python
静态编程语言
静态编程语言的变量有固定的类型,它们指的是内存中的值。Java、C、C++
介绍
反射机制
动态获取信息以及动态调用对象方法的功能。
提供的功能
- 运行时,判断任意一个对象所属类
- 运行时,构造任意一个类的对象
- 运行时,判断任意一个类所具有的成员方法和变量
- 运行时,调用任意一个对象的方法
- 生成动态代理
反射机制原理
RTTI 运行时类型信息
运行期间,Java通过Class对象记录每个对象RTTI,当编写并编译一个新类时,就会产生一个Class对象。
Class对象是在加载类时由JVM构造的,JVM为每个类管理一个独一无二的Class对象。
动态的生成字节码(.class文件),加载到JVM中运行。
使用的类
Class类
Class对象的由来是将class文件读入内存,并为之创建一个Class对象。
实例表示正在运行的Java应用程序中的类和接口。
获取Class对象:
- Object.getClass();
- Class.getSuperClass();
- Class.forName();
- 对于包装器类型:类名.TYPE属性。
Field类
提供有关类和接口的属性信息,以及对其动态访问权限。
Constructor类
提供类的单个构造方法信息,以及对其的访问权限。
Method类
提供类和接口单独的某个方法的信息。
功能使用
获取对象的类
getClass()
//1.1 getClass() //获取对象的类 String str = "hello world!"; cls = str.getClass(); System.out.println(cls.getName());
Class.forName()
- 类加载器加载方法
//1.2 Class.forName(); //根据具体包名来获取类 //字符串合法命名是类的命名空间和类的名称组成 cls = Class.forName("reflectprj.Student");
获取类的父类
Class
对象且该对象有父类//1.3 getSuperclass(); //获取类的父类 Class superCls = cls.getSuperclass();
获取类的构造方法
- 获取全部的构造方法
getDeclaredConstructors()
- 获取特定的构造方法
getDeclaredConstructor(Class[] class)
- 创建构造方法创建实例
newInstance(参数)
//3.1 getDeclaredConstructors(); //获取类的构造方法 Constructor[] constructors; constructors = cls.getDeclaredConstructors(); for(Constructor constructor:constructors) { System.out.println(constructor.toString()); } //3.1.2 //获取类特定的构造方法 Class[] var = {int.class,String.class,String.class}; Constructor constructor = cls.getDeclaredConstructor(var); System.out.println(constructor.toString()); //4.1 newInstance(); //通过构造方法创建实例 Student stu = (Student)constructor.newInstance(1,"王小明","man"); System.out.println(stu.toString());
获取类的方法
- 获取全部的方法
getDeclaredMethods()
- 获取特定的方法
getDeclaredMethod("方法名",Class[])
- 将对象与方法关联,并调用方法。
invoke(对象名,参数)
- 如果方法为私有,则调用
method.setAccessible(true)
//3.2 getDeclaredMethod(); //获取类的方法 Method [] ms = cls.getDeclaredMethods(); for(Method m:ms) { System.out.println(m.getName()); } //4.2 invoke(); //调用类的方法 Method m = cls.getDeclaredMethod("setSex", String.class); m.invoke(stu, "women"); System.out.println(stu.toString()); //5 setAccessible() //调用私有方法 m = cls.getDeclaredMethod("print", null); m.setAccessible(true); m.invoke(stu,null);
获取类的属性
- 获取全部的属性
getDeclaredFields()
- 获取特定的属性
getDeclaredField("fieldName")
- 将对象与属性关联,并设置属性
set(对象名,属性)
- 将对象与属性关联,获取属性
get(对象名)
- 如果属性为私有,则调用
method.setAccessible(true)
//3.3 getDeclaredField() //获取类的属性 Field fs[] = cls.getDeclaredFields(); for(Field f:fs) { System.out.println(f.getName()); } //4.3 set(); //设置私有类属性 Field f = cls.getDeclaredField("sex"); f.setAccessible(true); f.set(stu,"men"); System.out.println(f.get(stu).toString());
反射的应用
操作数据库
动态创建SQL语句。
public void save(Object obj) {
String sql = "insert into ";
try {
Class cls = obj.getClass();
String clsName = cls.getSimpleName();
sql+=clsName;
sql+="(";
Field fs[] = cls.getDeclaredFields();
for(Field f:fs) {
sql+=f.getName()+",";
}
sql = sql.substring(0, sql.length()-1);
sql+=") values(";
Field fs1[] = cls.getDeclaredFields();
for(Field f:fs1) {
f.setAccessible(true);
sql+=f.get(obj)+",";
}
sql = sql.substring(0, sql.length()-1);
sql+=")";
}catch(Exception e) {
e.printStackTrace();
}
System.out.println(sql);
}
解析XML
解析XML动态生成对象。(Spring框架)
动态代理
框架使用
- Spring框架
- Hibernate框架
- Struts框架
缺点
反射对于性能有影响,反射基本上是一种解释操作。
可以告诉JVM希望做什么,让其满足要求。
这类操作慢于直接执行相同的操作。