反射
Java的动态机制, 用于在运行期间检查对象的类型, 检查对象的类结构(属性,方法等), 还可以动态加载类, 动态创建对象, 动态访问属性和方法, 等.
反射是 Java 的API.
public void print(Object obj){
//利用反射API,动态检查obj引用的对象类型
Class cls = obj.getClass();
System.out.println(obj);
}
经典面试题目:
Eclipse 中快捷菜单采用了什么技术实现的?
答案: 反射技术, 反射API
反射的功能
- 动态加载类
- 动态创建对象
- 动态调用属性和方法
静态调用
如下程序编译后就已经确定了执行次序, 执行期间按照编译时候确定的执行顺序执行, 这个情况称为静态执行.
Foo foo = new Foo();
foo.test();
动态执行
Java 反射API提供了动态执行机制
- 动态加载类
- 动态创建对象
- 动态调用属性和方法
动态加载类
在程序运行之前不知道类名, 在运行期间动态根据类名加载类到内存(方法区)
Class cls = Class.forName(类名);
动态创建对象
如下方法可以动态创建类的一个实例
Object obj = cls.newInstance();
使用前提: cls代表的类必须存在无参数构造器! 如果没有无参数构造器则抛出异常.
反射中可以调用有参数构造器
必须使用反射实现的案例:
执行一个类中的全部以test为开头的方法, 这些方法都是非静态方法, 方法没有返回值,没有参数.
如上案例必须使用反射实现!
实现过程:
- 动态输入一个类名
- 动态加载类型
- 动态创建对象
- 利用反射查找全部方法信息
- 找到以test为开头方法
- 利用反射动态执行对象的方法
访问不可见方法
Java中的访问修饰词用于控制 方法和属性的可见范围. 称为封装特性.
反射API可以打破如上封装,实现访问不可见的方法和属性!
method.setAccessible(true);
动态调用有参数的方法
//找到方法
method=cls.getDeclaredMethod(方法名, 参数类型1, 参数类型2...)
//创建对象
obj=cls.newInstance();
//准备参数
Object method.invoke(obj, 参数1, 参数2, 参数3...)
素材:
class Goo{
public int test(int a){
return a+1;
}
public String demo(String s){
return s + "1";
}
public double demo(double d){
return d+1;
}
}
案例:
解耦
解除耦合性: 减低/解除 两段代码(两个组件)之间的耦合关系.
public void test(){
Foo foo = new Foo();
foo.test();
}
利用反射API, 可以实现一个组件与未来的一个组件的松散耦合. 甚至可以不在不知道类名不知道方法名的情况下实现调用关系.
动态访问对象的属性
Field 代表类中的属性信息
//读取对象obj的指定属性, 返回属性的值
Object Field.get(obj)
//设置属性的值
void Field.set(obj, value);
案例: 反射读取对象的一个属性
String className = in.nextLine();
String name = in.nextLine();
//动态加载类
Class cls = Class.forName(className);
//动态创建一个对象
Object obj = cls.newInstance();
//获取类的一个属性信息
fld = cls.getDeclaredField(name);
Object val = fld.get(obj);
System.out.println(val);
修改属性
//obj = foo(age=5, name=Tom)
//fld = age
//value = 10
//检查属性 age=10
String className = in.nextLine();
String name = in.nextLine();
String value = in.nextLine();
//动态加载类
Class cls = Class.forName(className);
//动态创建一个对象
Object obj = cls.newInstance();
//获取类的一个属性信息
fld = cls.getDeclaredField(name);
fld.set(obj, value);
System.out.println(obj);
经典案例
需求: 检查一个类是否包含 service(Request req, Response res)方法, 如果包含这个方法, 就执行这个方法. 不包含就抛出异常.
提示: 类名, Request对象, Response对象作为参数输入.
设计:
public void execute(String className, Request req,
Response res) throw Exception{
//动态加载类
//根据方法签名查找方法 "service" Request Response
//创建对象, 执行方法
}
这个设计的好处: 解耦
很多框架使用反射
框架为了解决对未来未知组件进行管理, 所有经常使用反射API