反射

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都有它的影子,反射虽然很灵活,能够使得写的代码,变的大幅精简。

优点

  1. 能够运行时动态获取类的实例,大大提高系统的灵活性和扩展性。
  2. 与Java动态编译相结合,可以实现无比强大的功能

缺点

  1. 使用反射的性能较低,反射相当于一系列解释操作,通知jvm要做的事情,性能比直接的java代码要慢很多
  2. 使用反射相对来说不安全
  3. 破坏了类的封装性,可以通过反射获取这个类的私有方法和属性

反射的功能:

  1. 得到一个对象所属的类
  2. 获取一个类的所有成员变量和方法
  3. 在运行时创建对象
  4. 在运行时调用对象方法

怎么使用反射?

怎么获取 Class 类?

  1. Class.forName("类的路径")
  2. 类.class
  3. 实例.getClass()

可以根据类模板实例化对象:Object obj=类模板对象.newInstance();//类模板对应的对象的字节码文件中必须有无参构造函数,否则报异常。


如何创建对象?

  1. new 实例化语言
  2. 通过反射机制创建对象
  3. 通过 clone() 方法创建一个对象
  4. 通过反序列化的方式创建对象

关于 Method:

如何获取 Method:

  1. getDeclaredMethods: 得到 Method 的数组.
  2. getDeclaredMethod(String methondName, Class ... parameterTypes)

如何调用 Method

  1. 如果方法时 private 修饰的, 需要先调用 Method 的 setAccessible(true), 使其变为可访问
  2. method.invoke(obj, Object ... args);

关于 Field:

  1. 如何获取 Field: getField(String fieldName)
  2. 如何获取 Field 的值: setAccessible(true)、field.get(Object obj)
  3. 如何设置 Field 的值: field.set(Obejct obj, Object val)

参考

https://blog.csdn.net/u010454030/article/details/45076721

https://www.cnblogs.com/tech-bird/p/3525336.html

posted @ 2018-08-01 14:21  罗贱人  阅读(173)  评论(0编辑  收藏  举报