Reflect 反射

Java 反射机制 是众多 框架的基础, 包括 MyBatis, Spring。

什么是反射?

反射 是在运行时动态访问类与对象的技术。一般情况下,新建一个对象需要用到 new 关键字。实际上, new 一个对象是写死在程序中的,不够灵活。有的业务场景, 并不知道什么时候能要实例化一个对象,也不知道应该实例化哪个对象。

举个例子。比如有这么一个 MathOperation, 用来处理两个 整形 数字的运算。

public interface MathOperation {
    public float operate(int a , int b);
}

有一个 Addition 类实现了 MathOperation 接口, 用于计算 两个整型数字相加并返回结果。

//加法
public class Addition implements MathOperation {
    @Override
    public float operate(int a , int b) {
        System.out.println("执行加法运算");
        return a + b;
    }
}

还有一个 Subtraction 类实现了 MathOperation 接口, 用于计算 两个整型数字相加并返回结果。

//减法
public class Subtraction implements  MathOperation{
    @Override
    public float operate(int a, int b) {
        System.out.println("执行减法运算");
        return a - b;
    }
}

我们写了一个测试类ReflectionDemo, 里面的有一个case1函数用来测试 Addition 和 Subtraction 功能 。case1 函数的功能非常简单, 在控制台输入运算种类, 然后输入两个数字 a 和 b ,实例化运算功能的对象,然后运算。

public class ReflectDemo {

    //不使用 反射, 在编译时决定创建哪几个对象
    public static void case1(){

        System.out.print("请输入运算名:");
        
        Scanner scanner = new Scanner(System.in);
        String op = scanner.next();
        
        System.out.print("请输入a:");
        int a = scanner.nextInt();
        System.out.print("请输入b:");
        int b = scanner.nextInt();
        
        MathOperation mathOperation = null;
        
        if(op.equals("Addition")){
            mathOperation = new Addition();
        }else if(op.equals("Subtraction")) {
            mathOperation = new Subtraction();
        }else{
            System.out.println("无效的计算类");
            return;
        }
        float result = mathOperation.operate(a, b);
        System.out.println(result);
        
    }
    
    public static void main(String[] args) {
        case2();

    }
}

这里实例化运算对象是写死在case1函数里面的,在编译这段代码时,计算机就已经知道接下来要实例化哪几个类。

假设我们需要新增加计算种类,比如 乘法: a*b , 除法: a/b,指数 a^b, 对数: loga,等等,我们只能在if-else 语句里面不断增加 else if 进行判断, 非常地麻烦。

有没有什么机制,可以在控制台输入运算名之前先不进行创建对象,或者是即使增加了很多运算种类,也不额外增加调用部分的代码。

答案是有的,Java 反射机制 可以解决这个问题。

第一段 Java 反射代码

我们在 ReflectDemo 类中追加一个 case2 函数。

 //使用 反射, 动态创建类
    public static void case2(){

        System.out.print("请输入运算名:");
        Scanner scanner = new Scanner(System.in);

        String op = scanner.next();
        System.out.print("请输入a:");
        int a = scanner.nextInt();
        System.out.print("请输入b:");
        int b = scanner.nextInt();
        MathOperation mathOperation = null;

        //用反射 机制 动态决定 创建哪一个 对象
        try {
            mathOperation = (MathOperation) Class.forName("indi.chester.reflectdemo." + op).newInstance();
        }catch(Exception e){
            System.out.println("无效的计算类");
            return;
        }
        float result = mathOperation.operate(a, b);
        System.out.println(result);
    }

case2 与 case1 函数大多数代码都是相同的,主要区别在于下面这一行行代码:

mathOperation = (MathOperation) Class.forName("indi.chester.reflectdemo." + op).newInstance();

这一行代码用到了一个 Class类里面的静态方法 forName( String className), 返回一个Class 对象,然后再利用这个 Class 对象调用 newInstance() 方法创建一个对象,返回的 Object 类型对象,需要对其进行强制类型转换,得到一个运算类型对象,也就是 Addition 对象 或者是 Subtraction 对象。

可以看出,在代码编译的时候, 程序并不知道应该创建哪几个对象,完全要等到在控制台输入后程序才知道。

以后无论我们增加 多少种 运算种类, case2 函数都不需要做任何改动, 实现了程序的可复用性和解耦。

Last updated