# Reflect 反射

## 什么是反射？

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

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

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

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

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

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

```java
//减法
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 ，实例化运算功能的对象，然后运算。

```java
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 函数。

```java
 //使用 反射, 动态创建类
    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 函数都不需要做任何改动, 实现了程序的可复用性和解耦。**
