反射
why ? when ? what? how ?
什么是反射?
反射允许程序在运行时进行自我检查,同时也允许对齐内部成员进行操作。通俗讲反射可以在运行时根据指定的类获取类的信息。
为什么要使用反射?
先明确两个概念,静态编译和动态编译
静态编译:在编译时确定类型,绑定对象。一次性编译。在编译的时候把你所有的模块都编译进去。
动态编译:运行时确定类型,绑定对象。按需编译。程序在运行的时候,用到那个模块就编译哪个模块。
反射可以实现动态创建对象和编译,体现出很大的灵活性。
如:简单工厂模式实现两个数的加减乘除
public class TestOperation {
public static void main(String[] args) {
int numA=10,numB=20;
char operation='+';
Factory.getResult(operation,numA,numB);
}
}
class Factory{
public static void getResult(char operation,int numA,int numB){
if(operation=='+'){
new AddOperation(numA,numB).getResult();
}else if(operation=='-'){
new SubtractionOperation(numA,numB).getResult();
}
}
}
abstract class Operation {
private int numA;
private int numB;
public Operation() {
}
public Operation(int numA, int numB) {
this.numA = numA;
this.numB = numB;
}
public int getNumA() {
return numA;
}
public void setNumA(int numA) {
this.numA = numA;
}
public int getNumB() {
return numB;
}
public void setNumB(int numB) {
this.numB = numB;
}
public abstract void getResult();
}
class AddOperation extends Operation{
public AddOperation(int numA,int numB){
super(numA,numB);
}
@Override
public void getResult() {
System.out.println("result: numA + numB ="+(getNumA()+getNumB()));
}
}
class SubtractionOperation extends Operation{
public SubtractionOperation(int numA,int numB){
super(numA,numB);
}
@Override
public void getResult() {
System.out.println("result: numA - numB ="+(getNumA()-getNumB()));
}
}
上面代码只实现了两个方法:加法和减法,要是再添加乘法除法类后,那么 Factory 是要在加上乘法和除法,如果还要再加点方法(取余、平方..)那么 Factory 类就会越来越臃肿。有没有好方法呢? 反射来了
class Factory {
public static void getResult(String className, int numA, int numB) {
AddOperation operation = null;
try {
operation = (AddOperation) Class.forName(className).newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
operation.setNumA(numA);
operation.setNumB(numB);
operation.getResult();
}
}
利用反射后 Factory类就不用修改,根据传入的类名来创建类型。
反射有哪些应用场景?
我们一般会用Class类,来调用这个被反射的Objcet类下的,构造方法,属性,或方法等,反射在一些开源框架里用的非常之多,Spring,Struts,Hibnerate,MyBatics都有它的影子,反射虽然很灵活,能够使得写的代码,变的大幅精简。
优点:
- 能够运行时动态获取类的实例,大大提高系统的灵活性和扩展性。
- 与Java动态编译相结合,可以实现无比强大的功能
缺点:
- 使用反射的性能较低,反射相当于一系列解释操作,通知jvm要做的事情,性能比直接的java代码要慢很多
- 使用反射相对来说不安全
- 破坏了类的封装性,可以通过反射获取这个类的私有方法和属性
反射的功能:
- 得到一个对象所属的类
- 获取一个类的所有成员变量和方法
- 在运行时创建对象
- 在运行时调用对象方法
怎么使用反射?
怎么获取 Class 类?
- Class.forName("类的路径")
- 类.class
- 实例.getClass()
可以根据类模板实例化对象:Object obj=类模板对象.newInstance();//类模板对应的对象的字节码文件中必须有无参构造函数,否则报异常。
如何创建对象?
- new 实例化语言
- 通过反射机制创建对象
- 通过 clone() 方法创建一个对象
- 通过反序列化的方式创建对象
关于 Method:
如何获取 Method:
- getDeclaredMethods: 得到 Method 的数组.
- getDeclaredMethod(String methondName, Class ... parameterTypes)
如何调用 Method
- 如果方法时 private 修饰的, 需要先调用 Method 的 setAccessible(true), 使其变为可访问
- method.invoke(obj, Object ... args);
关于 Field:
- 如何获取 Field: getField(String fieldName)
- 如何获取 Field 的值: setAccessible(true)、field.get(Object obj)
- 如何设置 Field 的值: field.set(Obejct obj, Object val)
参考
才学疏浅,有什么问题请大家指出来。十分感谢!